<commit_before>// Copyright 2014 BVLC and contributors.

#include <algorithm>
#include <cmath>
#include <cfloat>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <iomanip>

#include "caffe/layer.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/util/io.hpp"

using std::max;

namespace caffe {

template <typename Dtype>
void L2LossLayer<Dtype>::FurtherSetUp(
  const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
  CHECK_EQ(bottom[0]->channels(), bottom[1]->channels());
  CHECK_EQ(bottom[0]->height(), bottom[1]->height());
  CHECK_EQ(bottom[0]->width(), bottom[1]->width());
  diff_.Reshape(bottom[0]->num(), bottom[0]->channels(),
      bottom[0]->height(), bottom[0]->width());
}

template <typename Dtype>
Dtype L2LossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {
  int count = bottom[0]->count();
  const Dtype *data0 = bottom[0]->cpu_data();
  const Dtype *data1 = bottom[1]->cpu_data();
  for (int i = 0; i < 4; i++) {
    std::cout << data0[i] << ", " << data1[i] << std::endl;
  }
  caffe_sub(
      count,
      bottom[0]->cpu_data(),
      bottom[1]->cpu_data(),
      diff_.mutable_cpu_data());
  Dtype dot = caffe_cpu_dot(count, diff_.cpu_data(), diff_.cpu_data());
  Dtype loss = dot / bottom[0]->num() / Dtype(2);
  return loss;
}

template <typename Dtype>
void L2LossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
  caffe_cpu_axpby(
      (*bottom)[0]->count(),
      Dtype(1) / (*bottom)[0]->num(),
      diff_.cpu_data(),
      Dtype(0),
      (*bottom)[0]->mutable_cpu_diff());
}

template <typename Dtype>
void EuclideanLossLayer<Dtype>::FurtherSetUp(
  const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
  CHECK_EQ(bottom[0]->channels(), label_length_);
  CHECK_EQ(bottom[0]->height(), bottom[1]->height());
  CHECK_EQ(bottom[0]->width(), bottom[1]->width());
  diff_.Reshape(bottom[0]->num(), bottom[0]->channels(),
      bottom[0]->height(), bottom[0]->width());

  LOG(INFO)<<"START LOAD LABEL_CODE_TABLE";
  // label_length_=255;
  CHECK_EQ(bottom[0]->channels(), label_length_)
      << " predict output channels shoud be same as label code "<<std::endl;

  // label_class_num_=201;
  LOG(INFO)<<"Start load label_code_table file";
  std::ifstream infile(code_file_.c_str());
  CHECK(infile.good()) << "Failed to open target code file: " << code_file_ << std::endl;

  int label_class_num_ = label_length_;
  for(int i = 0; i < label_class_num_; ++i){
      // LOG(INFO)<< "START LOAD LABEL_CODE INDEX: "<<i<<"-"<<label_class_num_;
      vector<Dtype> label_code;
      for(int j = 0; j < label_length_; ++j){
          //LOG(INFO) << "start load label_code bit index: "<< j<<"-"<< label_length_;
          Dtype label_bit;
          infile >> label_bit;
          label_code.push_back(label_bit);
      }
      label_code_table_.push_back(label_code);
  }
  LOG(INFO)<<"END LOADING LABEL_CODE_TABLE";
  infile.close();
}

template <typename Dtype>
Dtype EuclideanLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {
  int count = bottom[0]->count();

  Blob<Dtype> gt_target_code(bottom[0]->num(),bottom[0]->channels(),bottom[0]->height(),bottom[0]->width());
  CHECK_EQ(bottom[0]->height(),1);
  CHECK_EQ(bottom[0]->width(),1);
  for(int i=0;i<bottom[0]->num();++i){
      for(int j=0;j<bottom[0]->channels();++j){
          *(gt_target_code.mutable_cpu_data() + gt_target_code.offset(i,j))
            = label_code_table_[bottom[1]->cpu_data()[i]][j];
      }
  }
  caffe_sub(
      count,
      bottom[0]->cpu_data(),
      gt_target_code.cpu_data(),
      diff_.mutable_cpu_data());

  // for (int i = 0; i < 10; i++) {
  //   std::cout << std::setprecision(3) << bottom[0]->cpu_data()[i] << ","
  //     << gt_target_code.cpu_data()[i] << "  ";
  // }
  // std::cout << std::endl;
  Dtype dot = caffe_cpu_dot(count, diff_.cpu_data(), diff_.cpu_data());
  Dtype loss = sqrt(dot / bottom[0]->num() / label_length_);
  //LOG(INFO)<< dot << " " << bottom[0]->num() << " " << bottom[0]->data_at(0, 0, 0, 0);
  return loss;
}

template <typename Dtype>
void EuclideanLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
  caffe_cpu_axpby(
      (*bottom)[0]->count(),              // count
      Dtype(1) / (*bottom)[0]->num(),     // alpha
      diff_.cpu_data(),                   // a
      Dtype(0),                           // beta
      (*bottom)[0]->mutable_cpu_diff());  // b
}

template <typename Dtype>
void TargetCodingHingeLossLayer<Dtype>::FurtherSetUp(
  const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
  CHECK_EQ(bottom[0]->channels(), label_length_);
  CHECK_EQ(bottom[0]->height(), bottom[1]->height());
  CHECK_EQ(bottom[0]->width(), bottom[1]->width());
  gt_label_code_.Reshape(bottom[0]->num(), bottom[0]->channels(),
            bottom[0]->height(), bottom[0]->width());

  LOG(INFO)<<"START LOAD LABEL_CODE_TABLE";
  // label_length_=255;
  CHECK_EQ(bottom[0]->channels(), label_length_)
      << " predict output channels shoud be same as label code "<<std::endl;

  std::ifstream infile(code_file_.c_str());
  CHECK(infile.good()) << "Failed to open target code file: " << code_file_ << std::endl;

  int label_class_num_ = label_length_;
  for(int i = 0; i < label_class_num_; ++i){
      vector<Dtype> label_code;
      for(int j = 0; j < label_length_; ++j){
          Dtype label_bit;
          infile >> label_bit;
          label_code.push_back(label_bit);
      }
      label_code_table_.push_back(label_code);
  }
  LOG(INFO)<<"END LOADING LABEL_CODE_TABLE";
  infile.close();
}

template <typename Dtype>
Dtype TargetCodingHingeLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {

  CHECK_EQ(bottom[0]->height(), 1);
  CHECK_EQ(bottom[0]->width(), 1);
  int num = bottom[0]->num();
  int count = bottom[0]->count();
  int dim = count / num;
  CHECK_EQ(dim, label_length_);
  const Dtype* bottom_data = bottom[0]->cpu_data();
  Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
  const Dtype* label = bottom[1]->cpu_data();
  Dtype* label_code = gt_label_code_.mutable_cpu_data();

  for(int i = 0; i < bottom[0]->num(); ++i){
      for(int j = 0; j < bottom[0]->channels(); ++j){
          *(label_code + gt_label_code_.offset(i,j))
            = label_code_table_[label[i]][j];
      }
  }

  caffe_copy(count, bottom_data, bottom_diff);
  caffe_add_scalar(count, Dtype(-0.5), bottom_diff); // b-0.5
  caffe_scal(count, Dtype(-2), label_code);
  caffe_add_scalar(count, Dtype(1), label_code);  // 1-2*gt
  caffe_mul(count, bottom_diff, label_code, bottom_diff);
  for (int i = 0; i < num; i++) {
    for (int j = 0; j < dim; j++) {
      bottom_diff[i * dim + j] = max(Dtype(0), margin_ + bottom_diff[i * dim + j]);
    }
  }

  //Dtype dot = caffe_cpu_dot(count, diff_.cpu_data(), diff_.cpu_data());
  Dtype loss = caffe_cpu_asum(count, bottom_diff) / num / label_length_; // hinge loss
  loss = Dtype(0.5) - margin_ + loss;  // loss relative to the groudtruth
  //LOG(INFO)<< dot << " " << bottom[0]->num() << " " << bottom[0]->data_at(0, 0, 0, 0);
  return loss;
}

template <typename Dtype>
void TargetCodingHingeLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
  Dtype *bottom_diff = (*bottom)[0]->mutable_cpu_diff();
  const Dtype *label_code = gt_label_code_.mutable_cpu_data();
  int num = (*bottom)[0]->num();
  int count = (*bottom)[0]->count();
  const Dtype* bottom_data = (*bottom)[0]->cpu_data();

  caffe_cpu_sign(count, bottom_diff, bottom_diff);
  caffe_mul(count, bottom_diff, label_code, bottom_diff);
  caffe_scal(count, Dtype(1. / num), bottom_diff);

  // for (int i = 512; i < 512 + 5; i++) {
  //   std::cout << std::setprecision(3) << bottom_data[i] << ","
  //     << label_code[i] << "," << bottom_diff[i] << "   ";
  // }
  // std::cout << std::endl;
}

INSTANTIATE_CLASS(L2LossLayer);

INSTANTIATE_CLASS(EuclideanLossLayer);

INSTANTIATE_CLASS(Euclidean1023LossLayer);

INSTANTIATE_CLASS(Euclidean255LossLayer);

INSTANTIATE_CLASS(TargetCodingHingeLossLayer);

INSTANTIATE_CLASS(TargetCoding1023HingeLossLayer);

}  // namespace caffe
<commit_msg>loss layer modified<commit_after>// Copyright 2014 BVLC and contributors.

#include <algorithm>
#include <cmath>
#include <cfloat>
#include <vector>
#include <string>
#include <fstream>
#include <iostream>
#include <iomanip>

#include "caffe/layer.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/util/io.hpp"

using std::max;

namespace caffe {

template <typename Dtype>
void L2LossLayer<Dtype>::FurtherSetUp(
  const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
  CHECK_EQ(bottom[0]->channels(), bottom[1]->channels());
  CHECK_EQ(bottom[0]->height(), bottom[1]->height());
  CHECK_EQ(bottom[0]->width(), bottom[1]->width());
  diff_.Reshape(bottom[0]->num(), bottom[0]->channels(),
      bottom[0]->height(), bottom[0]->width());
}

template <typename Dtype>
Dtype L2LossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {
  int count = bottom[0]->count();
  const Dtype *data0 = bottom[0]->cpu_data();
  const Dtype *data1 = bottom[1]->cpu_data();
  // for (int i = 0; i < 4; i++) {
  //   std::cout << data0[i] << ", " << data1[i] << std::endl;
  // }
  caffe_sub(
      count,
      bottom[0]->cpu_data(),
      bottom[1]->cpu_data(),
      diff_.mutable_cpu_data());
  Dtype dot = caffe_cpu_dot(count, diff_.cpu_data(), diff_.cpu_data());
  Dtype loss = dot / bottom[0]->num() / Dtype(2);
  return loss;
}

template <typename Dtype>
void L2LossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
  caffe_cpu_axpby(
      (*bottom)[0]->count(),
      Dtype(1) / (*bottom)[0]->num(),
      diff_.cpu_data(),
      Dtype(0),
      (*bottom)[0]->mutable_cpu_diff());
}

template <typename Dtype>
void EuclideanLossLayer<Dtype>::FurtherSetUp(
  const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
  CHECK_EQ(bottom[0]->channels(), label_length_);
  CHECK_EQ(bottom[0]->height(), bottom[1]->height());
  CHECK_EQ(bottom[0]->width(), bottom[1]->width());
  diff_.Reshape(bottom[0]->num(), bottom[0]->channels(),
      bottom[0]->height(), bottom[0]->width());

  LOG(INFO)<<"START LOAD LABEL_CODE_TABLE";
  // label_length_=255;
  CHECK_EQ(bottom[0]->channels(), label_length_)
      << " predict output channels shoud be same as label code "<<std::endl;

  // label_class_num_=201;
  LOG(INFO)<<"Start load label_code_table file";
  std::ifstream infile(code_file_.c_str());
  CHECK(infile.good()) << "Failed to open target code file: " << code_file_ << std::endl;

  int label_class_num_ = label_length_;
  for(int i = 0; i < label_class_num_; ++i){
      // LOG(INFO)<< "START LOAD LABEL_CODE INDEX: "<<i<<"-"<<label_class_num_;
      vector<Dtype> label_code;
      for(int j = 0; j < label_length_; ++j){
          //LOG(INFO) << "start load label_code bit index: "<< j<<"-"<< label_length_;
          Dtype label_bit;
          infile >> label_bit;
          label_code.push_back(label_bit);
      }
      label_code_table_.push_back(label_code);
  }
  LOG(INFO)<<"END LOADING LABEL_CODE_TABLE";
  infile.close();
}

template <typename Dtype>
Dtype EuclideanLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {
  int count = bottom[0]->count();

  Blob<Dtype> gt_target_code(bottom[0]->num(),bottom[0]->channels(),bottom[0]->height(),bottom[0]->width());
  CHECK_EQ(bottom[0]->height(),1);
  CHECK_EQ(bottom[0]->width(),1);
  for(int i=0;i<bottom[0]->num();++i){
      for(int j=0;j<bottom[0]->channels();++j){
          *(gt_target_code.mutable_cpu_data() + gt_target_code.offset(i,j))
            = label_code_table_[bottom[1]->cpu_data()[i]][j];
      }
  }
  caffe_sub(
      count,
      bottom[0]->cpu_data(),
      gt_target_code.cpu_data(),
      diff_.mutable_cpu_data());

  // for (int i = 0; i < 10; i++) {
  //   std::cout << std::setprecision(3) << bottom[0]->cpu_data()[i] << ","
  //     << gt_target_code.cpu_data()[i] << "  ";
  // }
  // std::cout << std::endl;
  Dtype dot = caffe_cpu_dot(count, diff_.cpu_data(), diff_.cpu_data());
  Dtype loss = sqrt(dot / bottom[0]->num() / label_length_);
  //LOG(INFO)<< dot << " " << bottom[0]->num() << " " << bottom[0]->data_at(0, 0, 0, 0);
  return loss;
}

template <typename Dtype>
void EuclideanLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
  caffe_cpu_axpby(
      (*bottom)[0]->count(),              // count
      Dtype(1) / (*bottom)[0]->num(),     // alpha
      diff_.cpu_data(),                   // a
      Dtype(0),                           // beta
      (*bottom)[0]->mutable_cpu_diff());  // b
}

template <typename Dtype>
void TargetCodingHingeLossLayer<Dtype>::FurtherSetUp(
  const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>* top) {
  CHECK_EQ(bottom[0]->channels(), label_length_);
  CHECK_EQ(bottom[0]->height(), bottom[1]->height());
  CHECK_EQ(bottom[0]->width(), bottom[1]->width());
  gt_label_code_.Reshape(bottom[0]->num(), bottom[0]->channels(),
            bottom[0]->height(), bottom[0]->width());

  LOG(INFO)<<"START LOAD LABEL_CODE_TABLE";
  // label_length_=255;
  CHECK_EQ(bottom[0]->channels(), label_length_)
      << " predict output channels shoud be same as label code "<<std::endl;

  std::ifstream infile(code_file_.c_str());
  CHECK(infile.good()) << "Failed to open target code file: " << code_file_ << std::endl;

  int label_class_num_ = label_length_;
  for(int i = 0; i < label_class_num_; ++i){
      vector<Dtype> label_code;
      for(int j = 0; j < label_length_; ++j){
          Dtype label_bit;
          infile >> label_bit;
          label_code.push_back(label_bit);
      }
      label_code_table_.push_back(label_code);
  }
  LOG(INFO)<<"END LOADING LABEL_CODE_TABLE";
  infile.close();
}

template <typename Dtype>
Dtype TargetCodingHingeLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
    vector<Blob<Dtype>*>* top) {

  CHECK_EQ(bottom[0]->height(), 1);
  CHECK_EQ(bottom[0]->width(), 1);
  int num = bottom[0]->num();
  int count = bottom[0]->count();
  int dim = count / num;
  CHECK_EQ(dim, label_length_);
  const Dtype* bottom_data = bottom[0]->cpu_data();
  Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
  const Dtype* label = bottom[1]->cpu_data();
  Dtype* label_code = gt_label_code_.mutable_cpu_data();

  for(int i = 0; i < bottom[0]->num(); ++i){
      for(int j = 0; j < bottom[0]->channels(); ++j){
          *(label_code + gt_label_code_.offset(i,j))
            = label_code_table_[label[i]][j];
      }
  }

  caffe_copy(count, bottom_data, bottom_diff);
  caffe_add_scalar(count, Dtype(-0.5), bottom_diff); // b-0.5
  caffe_scal(count, Dtype(-2), label_code);
  caffe_add_scalar(count, Dtype(1), label_code);  // 1-2*gt
  caffe_mul(count, bottom_diff, label_code, bottom_diff);
  for (int i = 0; i < num; i++) {
    for (int j = 0; j < dim; j++) {
      bottom_diff[i * dim + j] = max(Dtype(0), margin_ + bottom_diff[i * dim + j]);
    }
  }

  //Dtype dot = caffe_cpu_dot(count, diff_.cpu_data(), diff_.cpu_data());
  Dtype loss = caffe_cpu_asum(count, bottom_diff) / num / label_length_; // hinge loss
  loss = Dtype(0.5) - margin_ + loss;  // loss relative to the groudtruth
  //LOG(INFO)<< dot << " " << bottom[0]->num() << " " << bottom[0]->data_at(0, 0, 0, 0);
  return loss;
}

template <typename Dtype>
void TargetCodingHingeLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
  Dtype *bottom_diff = (*bottom)[0]->mutable_cpu_diff();
  const Dtype *label_code = gt_label_code_.mutable_cpu_data();
  int num = (*bottom)[0]->num();
  int count = (*bottom)[0]->count();
  const Dtype* bottom_data = (*bottom)[0]->cpu_data();

  caffe_cpu_sign(count, bottom_diff, bottom_diff);
  caffe_mul(count, bottom_diff, label_code, bottom_diff);
  caffe_scal(count, Dtype(1. / num), bottom_diff);

  // for (int i = 512; i < 512 + 5; i++) {
  //   std::cout << std::setprecision(3) << bottom_data[i] << ","
  //     << label_code[i] << "," << bottom_diff[i] << "   ";
  // }
  // std::cout << std::endl;
}

INSTANTIATE_CLASS(L2LossLayer);

INSTANTIATE_CLASS(EuclideanLossLayer);

INSTANTIATE_CLASS(Euclidean1023LossLayer);

INSTANTIATE_CLASS(Euclidean255LossLayer);

INSTANTIATE_CLASS(TargetCodingHingeLossLayer);

INSTANTIATE_CLASS(TargetCoding1023HingeLossLayer);

}  // namespace caffe
<|endoftext|>


<commit_before>/*
 * Copyright 2002-2010 Guillaume Cottenceau.
 *
 * This software may be freely redistributed under the terms
 * of the X11 license.
 *
 */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#define PNG_DEBUG 3
#include "png.h"

void abort_(const char * s, ...)
{
  va_list args;
  va_start(args, s);
  vfprintf(stderr, s, args);
  fprintf(stderr, "\n");
  va_end(args);
  abort();
}

int x, y;

int width, height;
png_byte color_type;
png_byte bit_depth;

png_structp png_ptr;
png_infop info_ptr;
int number_of_passes;
png_bytep * row_pointers = NULL;

// BGR or BGRA data will be read into this buffer of pixels

uint32_t *pixels = NULL;

const int debugPrintPixelsReadAndWritten = 0;

void allocate_row_pointers()
{
  if (row_pointers != NULL) {
    abort_("[allocate_row_pointers] row_pointers already allocated");
  }

  row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);

  if (!row_pointers) {
    abort_("[allocate_row_pointers] could not allocate %d bytes to store row data", (sizeof(png_bytep) * height));
  }

  for (y=0; y<height; y++) {
    row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));

    if (!row_pointers[y]) {
      abort_("[allocate_row_pointers] could not allocate %d bytes to store row data", png_get_rowbytes(png_ptr,info_ptr));
    }
  }
}

void free_row_pointers()
{
  if (row_pointers == NULL) {
    return;
  }

  for (y=0; y<height; y++)
    free(row_pointers[y]);
  free(row_pointers);
  row_pointers = NULL;
}

void read_png_file(char* file_name)
{
  char header[8];    // 8 is the maximum size that can be checked

  /* open file and test for it being a png */
  FILE *fp = fopen(file_name, "rb");
  if (!fp)
    abort_("[read_png_file] File %s could not be opened for reading", file_name);
  fread(header, 1, 8, fp);
  if (png_sig_cmp((png_const_bytep)header, 0, 8))
    abort_("[read_png_file] File %s is not recognized as a PNG file", file_name);

  /* initialize stuff */
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr)
    abort_("[read_png_file] png_create_read_struct failed");

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    abort_("[read_png_file] png_create_info_struct failed");

  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[read_png_file] Error during init_io");

  png_init_io(png_ptr, fp);
  png_set_sig_bytes(png_ptr, 8);

  png_read_info(png_ptr, info_ptr);

  width = png_get_image_width(png_ptr, info_ptr);
  height = png_get_image_height(png_ptr, info_ptr);
  color_type = png_get_color_type(png_ptr, info_ptr);
  bit_depth = png_get_bit_depth(png_ptr, info_ptr);

  number_of_passes = png_set_interlace_handling(png_ptr);
  png_read_update_info(png_ptr, info_ptr);

  /* read file */
  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[read_png_file] Error during read_image");

  allocate_row_pointers();

  png_read_image(png_ptr, row_pointers);

  /* allocate pixels data and read into array of pixels */

  pixels = (uint32_t*) malloc(width * height * sizeof(uint32_t));

  if (!pixels) {
    abort_("[read_png_file] could not allocate %d bytes to store pixel data", (width * height * sizeof(uint32_t)));
  }

  int pixeli = 0;

  int isBGRA = 0;

  if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGBA) {
    isBGRA = 1;
  } else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB) {
    isBGRA = 0;
  } else {
    abort_("[read_png_file] unsupported input format type");
  }

  for (y=0; y<height; y++) {
    png_byte* row = row_pointers[y];

    if (isBGRA) {
      for (x=0; x<width; x++) {
        png_byte* ptr = &(row[x*4]);

        uint32_t B = ptr[2];
        uint32_t G = ptr[1];
        uint32_t R = ptr[0];
        uint32_t A = ptr[3];

        uint32_t pixel = (A << 24) | (R << 16) | (G << 8) | B;

        if (debugPrintPixelsReadAndWritten) {
        fprintf(stdout, "Read pixel 0x%08X at (x,y) (%d, %d)\n", pixel, x, y);
        }

        pixels[pixeli] = pixel;

        pixeli++;
      }
    } else {
      // BGR with no alpha channel
      for (x=0; x<width; x++) {
        png_byte* ptr = &(row[x*3]);

        uint32_t B = ptr[2];
        uint32_t G = ptr[1];
        uint32_t R = ptr[0];

        uint32_t pixel = (0xFF << 24) | (R << 16) | (G << 8) | B;

        if (debugPrintPixelsReadAndWritten) {
        fprintf(stdout, "Read pixel 0x%08X at (x,y) (%d, %d)\n", pixel, x, y);
        }

        pixels[pixeli] = pixel;

        pixeli++;
      }
    }
  }

  fclose(fp);

  free_row_pointers();
}

void write_png_file(char* file_name)
{
  /* create file */
  FILE *fp = fopen(file_name, "wb");
  if (!fp)
    abort_("[write_png_file] File %s could not be opened for writing", file_name);

  /* initialize stuff */
  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr)
    abort_("[write_png_file] png_create_write_struct failed");

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    abort_("[write_png_file] png_create_info_struct failed");

  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[write_png_file] Error during init_io");

  png_init_io(png_ptr, fp);

  /* write header */
  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[write_png_file] Error during writing header");

  png_set_IHDR(png_ptr, info_ptr, width, height,
               bit_depth, color_type, PNG_INTERLACE_NONE,
               PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  png_write_info(png_ptr, info_ptr);

  /* write pixels back to row_pointers */

  allocate_row_pointers();

  int isBGRA = 0;

  if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGBA) {
    isBGRA = 1;
  } else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB) {
    isBGRA = 0;
  } else {
    abort_("[write_png_file] unsupported input format type");
  }

  int pixeli = 0;

  for (y=0; y<height; y++) {
    png_byte* row = row_pointers[y];

    if (isBGRA) {
      for (x=0; x<width; x++) {
        png_byte* ptr = &(row[x*4]);

        uint32_t pixel = pixels[pixeli];

        uint32_t B = pixel & 0xFF;
        uint32_t G = (pixel >> 8) & 0xFF;
        uint32_t R = (pixel >> 16) & 0xFF;
        uint32_t A = (pixel >> 24) & 0xFF;

        ptr[0] = R;
        ptr[1] = G;
        ptr[2] = B;
        ptr[3] = A;

        if (debugPrintPixelsReadAndWritten) {
        fprintf(stdout, "Wrote pixel 0x%08X at (x,y) (%d, %d)\n", pixel, x, y);
        }

        pixeli++;
      }
    } else {
      for (x=0; x<width; x++) {
        png_byte* ptr = &(row[x*3]);

        uint32_t pixel = pixels[pixeli];

        uint32_t B = pixel & 0xFF;
        uint32_t G = (pixel >> 8) & 0xFF;
        uint32_t R = (pixel >> 16) & 0xFF;

        ptr[0] = R;
        ptr[1] = G;
        ptr[2] = B;

        if (debugPrintPixelsReadAndWritten) {
        fprintf(stdout, "Wrote pixel 0x%08X at (x,y) (%d, %d)\n", pixel, x, y);
        }

        pixeli++;
      }
    }
  }

  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[write_png_file] Error during writing bytes");

  png_write_image(png_ptr, row_pointers);

  /* end write */
  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[write_png_file] Error during end of write");

  png_write_end(png_ptr, NULL);

  fclose(fp);
}

void process_file(void)
{
  // Swap the B and R channels in the BGRA format pixels

  int numPixels = width * height;

  for ( int i = 0; i < numPixels; i++) {
    uint32_t pixel = pixels[i];
    uint32_t B = pixel & 0xFF;
    uint32_t G = (pixel >> 8) & 0xFF;
    uint32_t R = (pixel >> 16) & 0xFF;
    uint32_t A = (pixel >> 24) & 0xFF;

    // Swap B and R channels

    if ((1)) {
      uint32_t tmp = B;
      B = R;
      R = tmp;
    }

    uint32_t outPixel = (A << 24) | (R << 16) | (G << 8) | B;

    pixels[i] = outPixel;
  }
}

/* deallocate memory */

void cleanup()
{
  free_row_pointers();

  free(pixels);
}

int main(int argc, char **argv)
{
  if (argc != 3) {
    abort_("Usage: %s <file_in> <file_out>", argv[0]);
  }

  read_png_file(argv[1]);
  process_file();
  write_png_file(argv[2]);

  cleanup();

  printf("success processing %d pixels from image of dimensions %d x %d\n", width*height, width, height);

  return 0;
}
<commit_msg>enable reading of grayscale image though a component swap would have no effect<commit_after>/*
 * Copyright 2002-2010 Guillaume Cottenceau.
 *
 * This software may be freely redistributed under the terms
 * of the X11 license.
 *
 */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#define PNG_DEBUG 3
#include "png.h"

void abort_(const char * s, ...)
{
  va_list args;
  va_start(args, s);
  vfprintf(stderr, s, args);
  fprintf(stderr, "\n");
  va_end(args);
  abort();
}

int x, y;

int width, height;
png_byte color_type;
png_byte bit_depth;

png_structp png_ptr;
png_infop info_ptr;
int number_of_passes;
png_bytep * row_pointers = NULL;

// BGR or BGRA data will be read into this buffer of pixels

uint32_t *pixels = NULL;

const int debugPrintPixelsReadAndWritten = 0;

void allocate_row_pointers()
{
  if (row_pointers != NULL) {
    abort_("[allocate_row_pointers] row_pointers already allocated");
  }

  row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);

  if (!row_pointers) {
    abort_("[allocate_row_pointers] could not allocate %d bytes to store row data", (sizeof(png_bytep) * height));
  }

  for (y=0; y<height; y++) {
    row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));

    if (!row_pointers[y]) {
      abort_("[allocate_row_pointers] could not allocate %d bytes to store row data", png_get_rowbytes(png_ptr,info_ptr));
    }
  }
}

void free_row_pointers()
{
  if (row_pointers == NULL) {
    return;
  }

  for (y=0; y<height; y++)
    free(row_pointers[y]);
  free(row_pointers);
  row_pointers = NULL;
}

void read_png_file(char* file_name)
{
  char header[8];    // 8 is the maximum size that can be checked

  /* open file and test for it being a png */
  FILE *fp = fopen(file_name, "rb");
  if (!fp)
    abort_("[read_png_file] File %s could not be opened for reading", file_name);
  fread(header, 1, 8, fp);
  if (png_sig_cmp((png_const_bytep)header, 0, 8))
    abort_("[read_png_file] File %s is not recognized as a PNG file", file_name);

  /* initialize stuff */
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr)
    abort_("[read_png_file] png_create_read_struct failed");

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    abort_("[read_png_file] png_create_info_struct failed");

  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[read_png_file] Error during init_io");

  png_init_io(png_ptr, fp);
  png_set_sig_bytes(png_ptr, 8);

  png_read_info(png_ptr, info_ptr);

  width = png_get_image_width(png_ptr, info_ptr);
  height = png_get_image_height(png_ptr, info_ptr);
  color_type = png_get_color_type(png_ptr, info_ptr);
  bit_depth = png_get_bit_depth(png_ptr, info_ptr);

  number_of_passes = png_set_interlace_handling(png_ptr);
  png_read_update_info(png_ptr, info_ptr);

  if (bit_depth != 8) {
    abort_("[read_png_file] only 8 bit pixel depth PNG is supported");
  }

  /* read file */
  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[read_png_file] Error during read_image");

  allocate_row_pointers();

  png_read_image(png_ptr, row_pointers);

  /* allocate pixels data and read into array of pixels */

  pixels = (uint32_t*) malloc(width * height * sizeof(uint32_t));

  if (!pixels) {
    abort_("[read_png_file] could not allocate %d bytes to store pixel data", (width * height * sizeof(uint32_t)));
  }

  int pixeli = 0;

  int isBGRA = 0;
  int isGrayscale = 0;

  if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGBA) {
    isBGRA = 1;
  } else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB) {
    isBGRA = 0;
  } else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY) {
    isGrayscale = 1;
  } else {
    abort_("[read_png_file] unsupported input format type");
  }

  for (y=0; y<height; y++) {
    png_byte* row = row_pointers[y];

    if (isGrayscale) {
      for (x=0; x<width; x++) {
        png_byte* ptr = &(row[x]);

        uint32_t gray = ptr[0];
        uint32_t pixel = (0xFF << 24) | (gray << 16) | (gray << 8) | gray;

        if (debugPrintPixelsReadAndWritten) {
          fprintf(stdout, "Read pixel 0x%08X at (x,y) (%d, %d)\n", pixel, x, y);
        }

        pixels[pixeli] = pixel;

        pixeli++;
      }
    } else if (isBGRA) {
      for (x=0; x<width; x++) {
        png_byte* ptr = &(row[x*4]);

        uint32_t B = ptr[2];
        uint32_t G = ptr[1];
        uint32_t R = ptr[0];
        uint32_t A = ptr[3];

        uint32_t pixel = (A << 24) | (R << 16) | (G << 8) | B;

        if (debugPrintPixelsReadAndWritten) {
        fprintf(stdout, "Read pixel 0x%08X at (x,y) (%d, %d)\n", pixel, x, y);
        }

        pixels[pixeli] = pixel;

        pixeli++;
      }
    } else {
      // BGR with no alpha channel
      for (x=0; x<width; x++) {
        png_byte* ptr = &(row[x*3]);

        uint32_t B = ptr[2];
        uint32_t G = ptr[1];
        uint32_t R = ptr[0];

        uint32_t pixel = (0xFF << 24) | (R << 16) | (G << 8) | B;

        if (debugPrintPixelsReadAndWritten) {
        fprintf(stdout, "Read pixel 0x%08X at (x,y) (%d, %d)\n", pixel, x, y);
        }

        pixels[pixeli] = pixel;

        pixeli++;
      }
    }
  }

  fclose(fp);

  free_row_pointers();
}

void write_png_file(char* file_name)
{
  /* create file */
  FILE *fp = fopen(file_name, "wb");
  if (!fp)
    abort_("[write_png_file] File %s could not be opened for writing", file_name);

  /* initialize stuff */
  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr)
    abort_("[write_png_file] png_create_write_struct failed");

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    abort_("[write_png_file] png_create_info_struct failed");

  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[write_png_file] Error during init_io");

  png_init_io(png_ptr, fp);

  /* write header */
  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[write_png_file] Error during writing header");

  png_set_IHDR(png_ptr, info_ptr, width, height,
               bit_depth, color_type, PNG_INTERLACE_NONE,
               PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  png_write_info(png_ptr, info_ptr);

  /* write pixels back to row_pointers */

  allocate_row_pointers();

  int isBGRA = 0;
  int isGrayscale = 0;

  if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGBA) {
    isBGRA = 1;
  } else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB) {
    isBGRA = 0;
  } else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY) {
    isGrayscale = 1;
  } else {
    abort_("[write_png_file] unsupported input format type");
  }

  int pixeli = 0;

  for (y=0; y<height; y++) {
    png_byte* row = row_pointers[y];

    if (isGrayscale) {
      for (x=0; x<width; x++) {
        png_byte* ptr = &(row[x]);

        uint32_t pixel = pixels[pixeli];

        uint32_t gray = pixel & 0xFF;

        ptr[0] = gray;

        if (debugPrintPixelsReadAndWritten) {
          fprintf(stdout, "Wrote pixel 0x%08X at (x,y) (%d, %d)\n", pixel, x, y);
        }

        pixeli++;
      }
    } else if (isBGRA) {
      for (x=0; x<width; x++) {
        png_byte* ptr = &(row[x*4]);

        uint32_t pixel = pixels[pixeli];

        uint32_t B = pixel & 0xFF;
        uint32_t G = (pixel >> 8) & 0xFF;
        uint32_t R = (pixel >> 16) & 0xFF;
        uint32_t A = (pixel >> 24) & 0xFF;

        ptr[0] = R;
        ptr[1] = G;
        ptr[2] = B;
        ptr[3] = A;

        if (debugPrintPixelsReadAndWritten) {
        fprintf(stdout, "Wrote pixel 0x%08X at (x,y) (%d, %d)\n", pixel, x, y);
        }

        pixeli++;
      }
    } else {
      for (x=0; x<width; x++) {
        png_byte* ptr = &(row[x*3]);

        uint32_t pixel = pixels[pixeli];

        uint32_t B = pixel & 0xFF;
        uint32_t G = (pixel >> 8) & 0xFF;
        uint32_t R = (pixel >> 16) & 0xFF;

        ptr[0] = R;
        ptr[1] = G;
        ptr[2] = B;

        if (debugPrintPixelsReadAndWritten) {
        fprintf(stdout, "Wrote pixel 0x%08X at (x,y) (%d, %d)\n", pixel, x, y);
        }

        pixeli++;
      }
    }
  }

  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[write_png_file] Error during writing bytes");

  png_write_image(png_ptr, row_pointers);

  /* end write */
  if (setjmp(png_jmpbuf(png_ptr)))
    abort_("[write_png_file] Error during end of write");

  png_write_end(png_ptr, NULL);

  fclose(fp);
}

void process_file(void)
{
  // Swap the B and R channels in the BGRA format pixels

  int numPixels = width * height;

  for ( int i = 0; i < numPixels; i++) {
    uint32_t pixel = pixels[i];
    uint32_t B = pixel & 0xFF;
    uint32_t G = (pixel >> 8) & 0xFF;
    uint32_t R = (pixel >> 16) & 0xFF;
    uint32_t A = (pixel >> 24) & 0xFF;

    // Swap B and R channels, a grayscale image will not be modified

    if ((1)) {
      uint32_t tmp = B;
      B = R;
      R = tmp;
    }

    uint32_t outPixel = (A << 24) | (R << 16) | (G << 8) | B;

    pixels[i] = outPixel;
  }
}

/* deallocate memory */

void cleanup()
{
  free_row_pointers();

  free(pixels);
}

int main(int argc, char **argv)
{
  if (argc != 3) {
    abort_("Usage: %s <in_png> <out_png>", argv[0]);
  }

  read_png_file(argv[1]);
  process_file();
  write_png_file(argv[2]);

  cleanup();

  printf("success processing %d pixels from image of dimensions %d x %d\n", width*height, width, height);

  return 0;
}
<|endoftext|>


<commit_before>/*ckwg +5
 * Copyright 2012 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include <viscl/core/manager.h>

#include <iostream>
#include <sstream>

namespace viscl
{

manager *manager::inst_ = 0;

//*****************************************************************************

manager *manager::inst()
{
  return inst_ ? inst_ : inst_ = new manager;
}

//*****************************************************************************

manager::manager()
{
  init_opencl();
}

//*****************************************************************************

void manager::init_opencl()
{
  try
  {
    // Get available platforms
    cl::Platform::get(&platforms_);

    /// \todo Add Windows support.
    std::stringstream platform;
    char* def_platform = getenv("VISCL_DEFAULT_PLATFORM");

    if (def_platform)
    {
      platform << def_platform;
    }

    size_t platform_id = DEFAULT_PLATFORM;
    platform >> platform_id;

    // Select the default platform and create a context using this platform and the GPU
    cl_context_properties cps[3] = {
        CL_CONTEXT_PLATFORM,
        (cl_context_properties)(platforms_[platform_id])(),
        0
    };

    context_ =  cl::Context(CL_DEVICE_TYPE_GPU, cps);

    // Get a list of devices on this platform
    devices_ = context_.getInfo<CL_CONTEXT_DEVICES>();
  }
  catch(cl::Error &error)
  {
    std::cout << "Error: " << error.what() << " - " << print_cl_errstring(error.err()) << std::endl;
  }
}

//*****************************************************************************

cl_program_t manager::build_source(const char *source, int device) const
{
  cl::Program::Sources src(1, std::make_pair(source, strlen(source)+1));

  // Make program of the source code in the context
  cl_program_t program = boost::make_shared<cl::Program>(cl::Program(context_, src));

  // Build program for these specific devices
  try {
    program->build(devices_);
  }
  catch(cl::Error error)  {
    if(error.err() == CL_BUILD_PROGRAM_FAILURE)
    {
      std::string build_log = program->getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices_[device]);
      std::cerr << build_log << std::endl;
    }
    throw error;
  }

  return program;
}

//*****************************************************************************

cl_queue_t manager::create_queue(int device)
{
  return boost::make_shared<cl::CommandQueue>(cl::CommandQueue(context_, devices_[device]));
}

//*****************************************************************************

image manager::create_image(const cl::ImageFormat &img_frmt, cl_mem_flags flags, size_t ni, size_t nj)
{
  return image(boost::make_shared<cl::Image2D>(cl::Image2D(context_,
                                                              flags,
                                                              img_frmt,
                                                              ni,
                                                              nj,
                                                              0,
                                                              0)));
}

//*****************************************************************************

void manager::report_device_specs(const cl::Device& dev,
                                     const std::string& prefix)
{
  try
  {
    std::cout << prefix << "Name                : "
              << dev.getInfo<CL_DEVICE_NAME>() << "\n";
    std::cout << prefix << "Type                : ";
    cl_device_type type = dev.getInfo<CL_DEVICE_TYPE>();
    if (type & CL_DEVICE_TYPE_CPU)
    {
      std::cout << "CPU ";
    }
    if (type & CL_DEVICE_TYPE_GPU)
    {
      std::cout << "GPU ";
    }
    if (type & CL_DEVICE_TYPE_ACCELERATOR)
    {
      std::cout << "Accelerator ";
    }
    std::cout << "\n";
    std::cout << prefix << "Vendor              : "
              << dev.getInfo<CL_DEVICE_VENDOR>() << "\n";
    std::cout << prefix << "Device Version      : "
              << dev.getInfo<CL_DEVICE_VERSION>() << "\n";
    std::cout << prefix << "Driver Version      : "
              << dev.getInfo<CL_DRIVER_VERSION>() << "\n";
    std::cout << prefix << "Max Clock Frequency : "
              << dev.getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>() << " MHz\n";
    std::cout << prefix << "Max Compute Units   : "
              << dev.getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>() << "\n";
    std::cout << prefix << "Max Work Item Dims  : "
              << dev.getInfo<CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS>() << "\n";
    std::cout << prefix << "Max Work Item Sizes : ";
    std::vector<size_t> work_sizes = dev.getInfo<CL_DEVICE_MAX_WORK_ITEM_SIZES>();
    for (size_t i=0; i<work_sizes.size(); ++i)
    {
      std::cout << work_sizes[i];
      if (i < work_sizes.size()-1)
      {
        std::cout << ", ";
      }
    }
    std::cout << "\n";
    std::cout << prefix << "Max Work Group Size : "
              << dev.getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>() << "\n";
    std::cout << prefix << "Global Memory       : "
              << dev.getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>()/1048576 << " Mb\n";
    std::cout << prefix << "Max Memory Alloc    : "
              << dev.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>()/1048576 << " Mb\n";
    std::cout << prefix << "Max Image 2D Dims   : "
              << dev.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() << " x "
              << dev.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() << "\n";
    std::cout << prefix << "Max Image 3D Dims   : "
              << dev.getInfo<CL_DEVICE_IMAGE3D_MAX_WIDTH>() << " x "
              << dev.getInfo<CL_DEVICE_IMAGE3D_MAX_HEIGHT>() << " x "
              << dev.getInfo<CL_DEVICE_IMAGE3D_MAX_DEPTH>() << "\n";
    std::cout << prefix << "Out of Order Queue  : "
              << ((dev.getInfo<CL_DEVICE_QUEUE_PROPERTIES>() &
                  CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE) ? "Yes" : "No") << "\n";

    std::string dev_ext = dev.getInfo<CL_DEVICE_EXTENSIONS>();
    std::istringstream extensions(dev_ext);
    std::string extension;
    std::cout << prefix << "Extensions          : ";
    bool first_ext = true;
    while (extensions >> extension)
    {
      if (first_ext)
      {
        first_ext = false;
      }
      else
      {
        std::cout << prefix << "                      ";
      }
      std::cout << extension << "\n";
    }
  }
  catch (cl::Error error)
  {
    std::cout << "Error: " << error.what() << " - "
             << print_cl_errstring(error.err()) << std::endl;
  }
}

//*****************************************************************************

void manager::report_opencl_specs()
{
  try
  {
    std::cout << "Found " << platforms_.size() << " Platforms" << std::endl;
    for (size_t i=0; i<platforms_.size(); ++i)
    {
      std::cout << "Platform[" << i << "]\n";
      std::cout << "  Name       : "
                << platforms_[i].getInfo<CL_PLATFORM_NAME>() << "\n";
      std::cout << "  Vendor     : "
                << platforms_[i].getInfo<CL_PLATFORM_VENDOR>() << "\n";
      std::cout << "  Version    : "
                << platforms_[i].getInfo<CL_PLATFORM_VERSION>() << "\n";
      std::cout << "  Profile    : "
                << platforms_[i].getInfo<CL_PLATFORM_PROFILE>() << "\n";
      std::string plat_ext = platforms_[i].getInfo<CL_PLATFORM_EXTENSIONS>();
      std::istringstream extensions(plat_ext);

      std::string extension;
      std::cout << "  Extensions : ";
      bool first_ext = true;
      while (extensions >> extension)
      {
        if (first_ext)
        {
          first_ext = false;
        }
        else
        {
          std::cout << "               ";
        }
        std::cout << extension << "\n";
      }

      std::vector<cl::Device> devices;
      platforms_[i].getDevices(CL_DEVICE_TYPE_ALL, &devices);
      std::cout << "  Found " << devices.size() << " Devices" << std::endl;
      for (size_t j=0; j<devices.size(); ++j)
      {
        std::cout << "\n  Device[" << j << "]\n";
        report_device_specs(devices[j], "    ");
      }
    }
  }
  catch (cl::Error error)
  {
    std::cout << "Error: " << error.what() << " - "
              << print_cl_errstring(error.err()) << std::endl;
  }
}

//*****************************************************************************

//Returns an error string explaining an error code
const char *print_cl_errstring(cl_int err)
{
    switch (err) {
        case CL_SUCCESS:                          return "Success";
        case CL_DEVICE_NOT_FOUND:                 return "Device not found";
        case CL_DEVICE_NOT_AVAILABLE:             return "Device not available";
        case CL_COMPILER_NOT_AVAILABLE:           return "Compiler not available";
        case CL_MEM_OBJECT_ALLOCATION_FAILURE:    return "Memory object allocation failure";
        case CL_OUT_OF_RESOURCES:                 return "Out of resources";
        case CL_OUT_OF_HOST_MEMORY:               return "Out of host memory";
        case CL_PROFILING_INFO_NOT_AVAILABLE:     return "Profiling information not available";
        case CL_MEM_COPY_OVERLAP:                 return "Memory copy overlap";
        case CL_IMAGE_FORMAT_MISMATCH:            return "Image format mismatch";
        case CL_IMAGE_FORMAT_NOT_SUPPORTED:       return "Image format not supported";
        case CL_BUILD_PROGRAM_FAILURE:            return "Program build failure";
        case CL_MAP_FAILURE:                      return "Map failure";
        case CL_INVALID_VALUE:                    return "Invalid value";
        case CL_INVALID_DEVICE_TYPE:              return "Invalid device type";
        case CL_INVALID_PLATFORM:                 return "Invalid platform";
        case CL_INVALID_DEVICE:                   return "Invalid device";
        case CL_INVALID_CONTEXT:                  return "Invalid context";
        case CL_INVALID_QUEUE_PROPERTIES:         return "Invalid queue properties";
        case CL_INVALID_COMMAND_QUEUE:            return "Invalid command queue";
        case CL_INVALID_HOST_PTR:                 return "Invalid host pointer";
        case CL_INVALID_MEM_OBJECT:               return "Invalid memory object";
        case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR:  return "Invalid image format descriptor";
        case CL_INVALID_IMAGE_SIZE:               return "Invalid image size";
        case CL_INVALID_SAMPLER:                  return "Invalid sampler";
        case CL_INVALID_BINARY:                   return "Invalid binary";
        case CL_INVALID_BUILD_OPTIONS:            return "Invalid build options";
        case CL_INVALID_PROGRAM:                  return "Invalid program";
        case CL_INVALID_PROGRAM_EXECUTABLE:       return "Invalid program executable";
        case CL_INVALID_KERNEL_NAME:              return "Invalid kernel name";
        case CL_INVALID_KERNEL_DEFINITION:        return "Invalid kernel definition";
        case CL_INVALID_KERNEL:                   return "Invalid kernel";
        case CL_INVALID_ARG_INDEX:                return "Invalid argument index";
        case CL_INVALID_ARG_VALUE:                return "Invalid argument value";
        case CL_INVALID_ARG_SIZE:                 return "Invalid argument size";
        case CL_INVALID_KERNEL_ARGS:              return "Invalid kernel arguments";
        case CL_INVALID_WORK_DIMENSION:           return "Invalid work dimension";
        case CL_INVALID_WORK_GROUP_SIZE:          return "Invalid work group size";
        case CL_INVALID_WORK_ITEM_SIZE:           return "Invalid work item size";
        case CL_INVALID_GLOBAL_OFFSET:            return "Invalid global offset";
        case CL_INVALID_EVENT_WAIT_LIST:          return "Invalid event wait list";
        case CL_INVALID_EVENT:                    return "Invalid event";
        case CL_INVALID_OPERATION:                return "Invalid operation";
        case CL_INVALID_GL_OBJECT:                return "Invalid OpenGL object";
        case CL_INVALID_BUFFER_SIZE:              return "Invalid buffer size";
        case CL_INVALID_MIP_LEVEL:                return "Invalid mip-map level";
        default:                                  return "Unknown";
    }
}

}
<commit_msg>Use boost::lexical_cast to parse the platform<commit_after>/*ckwg +5
 * Copyright 2012 by Kitware, Inc. All Rights Reserved. Please refer to
 * KITWARE_LICENSE.TXT for licensing information, or contact General Counsel,
 * Kitware, Inc., 28 Corporate Drive, Clifton Park, NY 12065.
 */

#include <viscl/core/manager.h>

#include <boost/lexical_cast.hpp>

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

namespace viscl
{

manager *manager::inst_ = 0;

//*****************************************************************************

manager *manager::inst()
{
  return inst_ ? inst_ : inst_ = new manager;
}

//*****************************************************************************

manager::manager()
{
  init_opencl();
}

//*****************************************************************************

void manager::init_opencl()
{
  try
  {
    // Get available platforms
    cl::Platform::get(&platforms_);

    /// \todo Add Windows support.
    char* def_platform = getenv("VISCL_DEFAULT_PLATFORM");

    size_t platform_id = DEFAULT_PLATFORM;
    if (def_platform)
    {
      try
      {
        platform_id = boost::lexical_cast<size_t>(def_platform);
      }
      catch (boost::bad_lexical_cast const& e)
      {
        std::string const reason = std::string("Failed to parse the platform: ") + e.what();

        throw std::runtime_error(reason);
      }
    }

    // Select the default platform and create a context using this platform and the GPU
    cl_context_properties cps[3] = {
        CL_CONTEXT_PLATFORM,
        (cl_context_properties)(platforms_[platform_id])(),
        0
    };

    context_ =  cl::Context(CL_DEVICE_TYPE_GPU, cps);

    // Get a list of devices on this platform
    devices_ = context_.getInfo<CL_CONTEXT_DEVICES>();
  }
  catch(cl::Error &error)
  {
    std::cout << "Error: " << error.what() << " - " << print_cl_errstring(error.err()) << std::endl;
  }
}

//*****************************************************************************

cl_program_t manager::build_source(const char *source, int device) const
{
  cl::Program::Sources src(1, std::make_pair(source, strlen(source)+1));

  // Make program of the source code in the context
  cl_program_t program = boost::make_shared<cl::Program>(cl::Program(context_, src));

  // Build program for these specific devices
  try {
    program->build(devices_);
  }
  catch(cl::Error error)  {
    if(error.err() == CL_BUILD_PROGRAM_FAILURE)
    {
      std::string build_log = program->getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices_[device]);
      std::cerr << build_log << std::endl;
    }
    throw error;
  }

  return program;
}

//*****************************************************************************

cl_queue_t manager::create_queue(int device)
{
  return boost::make_shared<cl::CommandQueue>(cl::CommandQueue(context_, devices_[device]));
}

//*****************************************************************************

image manager::create_image(const cl::ImageFormat &img_frmt, cl_mem_flags flags, size_t ni, size_t nj)
{
  return image(boost::make_shared<cl::Image2D>(cl::Image2D(context_,
                                                              flags,
                                                              img_frmt,
                                                              ni,
                                                              nj,
                                                              0,
                                                              0)));
}

//*****************************************************************************

void manager::report_device_specs(const cl::Device& dev,
                                     const std::string& prefix)
{
  try
  {
    std::cout << prefix << "Name                : "
              << dev.getInfo<CL_DEVICE_NAME>() << "\n";
    std::cout << prefix << "Type                : ";
    cl_device_type type = dev.getInfo<CL_DEVICE_TYPE>();
    if (type & CL_DEVICE_TYPE_CPU)
    {
      std::cout << "CPU ";
    }
    if (type & CL_DEVICE_TYPE_GPU)
    {
      std::cout << "GPU ";
    }
    if (type & CL_DEVICE_TYPE_ACCELERATOR)
    {
      std::cout << "Accelerator ";
    }
    std::cout << "\n";
    std::cout << prefix << "Vendor              : "
              << dev.getInfo<CL_DEVICE_VENDOR>() << "\n";
    std::cout << prefix << "Device Version      : "
              << dev.getInfo<CL_DEVICE_VERSION>() << "\n";
    std::cout << prefix << "Driver Version      : "
              << dev.getInfo<CL_DRIVER_VERSION>() << "\n";
    std::cout << prefix << "Max Clock Frequency : "
              << dev.getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>() << " MHz\n";
    std::cout << prefix << "Max Compute Units   : "
              << dev.getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>() << "\n";
    std::cout << prefix << "Max Work Item Dims  : "
              << dev.getInfo<CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS>() << "\n";
    std::cout << prefix << "Max Work Item Sizes : ";
    std::vector<size_t> work_sizes = dev.getInfo<CL_DEVICE_MAX_WORK_ITEM_SIZES>();
    for (size_t i=0; i<work_sizes.size(); ++i)
    {
      std::cout << work_sizes[i];
      if (i < work_sizes.size()-1)
      {
        std::cout << ", ";
      }
    }
    std::cout << "\n";
    std::cout << prefix << "Max Work Group Size : "
              << dev.getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>() << "\n";
    std::cout << prefix << "Global Memory       : "
              << dev.getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>()/1048576 << " Mb\n";
    std::cout << prefix << "Max Memory Alloc    : "
              << dev.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>()/1048576 << " Mb\n";
    std::cout << prefix << "Max Image 2D Dims   : "
              << dev.getInfo<CL_DEVICE_IMAGE2D_MAX_WIDTH>() << " x "
              << dev.getInfo<CL_DEVICE_IMAGE2D_MAX_HEIGHT>() << "\n";
    std::cout << prefix << "Max Image 3D Dims   : "
              << dev.getInfo<CL_DEVICE_IMAGE3D_MAX_WIDTH>() << " x "
              << dev.getInfo<CL_DEVICE_IMAGE3D_MAX_HEIGHT>() << " x "
              << dev.getInfo<CL_DEVICE_IMAGE3D_MAX_DEPTH>() << "\n";
    std::cout << prefix << "Out of Order Queue  : "
              << ((dev.getInfo<CL_DEVICE_QUEUE_PROPERTIES>() &
                  CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE) ? "Yes" : "No") << "\n";

    std::string dev_ext = dev.getInfo<CL_DEVICE_EXTENSIONS>();
    std::istringstream extensions(dev_ext);
    std::string extension;
    std::cout << prefix << "Extensions          : ";
    bool first_ext = true;
    while (extensions >> extension)
    {
      if (first_ext)
      {
        first_ext = false;
      }
      else
      {
        std::cout << prefix << "                      ";
      }
      std::cout << extension << "\n";
    }
  }
  catch (cl::Error error)
  {
    std::cout << "Error: " << error.what() << " - "
             << print_cl_errstring(error.err()) << std::endl;
  }
}

//*****************************************************************************

void manager::report_opencl_specs()
{
  try
  {
    std::cout << "Found " << platforms_.size() << " Platforms" << std::endl;
    for (size_t i=0; i<platforms_.size(); ++i)
    {
      std::cout << "Platform[" << i << "]\n";
      std::cout << "  Name       : "
                << platforms_[i].getInfo<CL_PLATFORM_NAME>() << "\n";
      std::cout << "  Vendor     : "
                << platforms_[i].getInfo<CL_PLATFORM_VENDOR>() << "\n";
      std::cout << "  Version    : "
                << platforms_[i].getInfo<CL_PLATFORM_VERSION>() << "\n";
      std::cout << "  Profile    : "
                << platforms_[i].getInfo<CL_PLATFORM_PROFILE>() << "\n";
      std::string plat_ext = platforms_[i].getInfo<CL_PLATFORM_EXTENSIONS>();
      std::istringstream extensions(plat_ext);

      std::string extension;
      std::cout << "  Extensions : ";
      bool first_ext = true;
      while (extensions >> extension)
      {
        if (first_ext)
        {
          first_ext = false;
        }
        else
        {
          std::cout << "               ";
        }
        std::cout << extension << "\n";
      }

      std::vector<cl::Device> devices;
      platforms_[i].getDevices(CL_DEVICE_TYPE_ALL, &devices);
      std::cout << "  Found " << devices.size() << " Devices" << std::endl;
      for (size_t j=0; j<devices.size(); ++j)
      {
        std::cout << "\n  Device[" << j << "]\n";
        report_device_specs(devices[j], "    ");
      }
    }
  }
  catch (cl::Error error)
  {
    std::cout << "Error: " << error.what() << " - "
              << print_cl_errstring(error.err()) << std::endl;
  }
}

//*****************************************************************************

//Returns an error string explaining an error code
const char *print_cl_errstring(cl_int err)
{
    switch (err) {
        case CL_SUCCESS:                          return "Success";
        case CL_DEVICE_NOT_FOUND:                 return "Device not found";
        case CL_DEVICE_NOT_AVAILABLE:             return "Device not available";
        case CL_COMPILER_NOT_AVAILABLE:           return "Compiler not available";
        case CL_MEM_OBJECT_ALLOCATION_FAILURE:    return "Memory object allocation failure";
        case CL_OUT_OF_RESOURCES:                 return "Out of resources";
        case CL_OUT_OF_HOST_MEMORY:               return "Out of host memory";
        case CL_PROFILING_INFO_NOT_AVAILABLE:     return "Profiling information not available";
        case CL_MEM_COPY_OVERLAP:                 return "Memory copy overlap";
        case CL_IMAGE_FORMAT_MISMATCH:            return "Image format mismatch";
        case CL_IMAGE_FORMAT_NOT_SUPPORTED:       return "Image format not supported";
        case CL_BUILD_PROGRAM_FAILURE:            return "Program build failure";
        case CL_MAP_FAILURE:                      return "Map failure";
        case CL_INVALID_VALUE:                    return "Invalid value";
        case CL_INVALID_DEVICE_TYPE:              return "Invalid device type";
        case CL_INVALID_PLATFORM:                 return "Invalid platform";
        case CL_INVALID_DEVICE:                   return "Invalid device";
        case CL_INVALID_CONTEXT:                  return "Invalid context";
        case CL_INVALID_QUEUE_PROPERTIES:         return "Invalid queue properties";
        case CL_INVALID_COMMAND_QUEUE:            return "Invalid command queue";
        case CL_INVALID_HOST_PTR:                 return "Invalid host pointer";
        case CL_INVALID_MEM_OBJECT:               return "Invalid memory object";
        case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR:  return "Invalid image format descriptor";
        case CL_INVALID_IMAGE_SIZE:               return "Invalid image size";
        case CL_INVALID_SAMPLER:                  return "Invalid sampler";
        case CL_INVALID_BINARY:                   return "Invalid binary";
        case CL_INVALID_BUILD_OPTIONS:            return "Invalid build options";
        case CL_INVALID_PROGRAM:                  return "Invalid program";
        case CL_INVALID_PROGRAM_EXECUTABLE:       return "Invalid program executable";
        case CL_INVALID_KERNEL_NAME:              return "Invalid kernel name";
        case CL_INVALID_KERNEL_DEFINITION:        return "Invalid kernel definition";
        case CL_INVALID_KERNEL:                   return "Invalid kernel";
        case CL_INVALID_ARG_INDEX:                return "Invalid argument index";
        case CL_INVALID_ARG_VALUE:                return "Invalid argument value";
        case CL_INVALID_ARG_SIZE:                 return "Invalid argument size";
        case CL_INVALID_KERNEL_ARGS:              return "Invalid kernel arguments";
        case CL_INVALID_WORK_DIMENSION:           return "Invalid work dimension";
        case CL_INVALID_WORK_GROUP_SIZE:          return "Invalid work group size";
        case CL_INVALID_WORK_ITEM_SIZE:           return "Invalid work item size";
        case CL_INVALID_GLOBAL_OFFSET:            return "Invalid global offset";
        case CL_INVALID_EVENT_WAIT_LIST:          return "Invalid event wait list";
        case CL_INVALID_EVENT:                    return "Invalid event";
        case CL_INVALID_OPERATION:                return "Invalid operation";
        case CL_INVALID_GL_OBJECT:                return "Invalid OpenGL object";
        case CL_INVALID_BUFFER_SIZE:              return "Invalid buffer size";
        case CL_INVALID_MIP_LEVEL:                return "Invalid mip-map level";
        default:                                  return "Unknown";
    }
}

}
<|endoftext|>


<commit_before>#include "bitflags.h"

namespace gcpp
{
constexpr byte bitflags::ALL_TRUE;
constexpr byte bitflags::ALL_FALSE;
}
<commit_msg>Keeping it header-only<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <c++/stdexcept>
#include "queue_ui.h"

using namespace std;

/**
 * Конструктор. Принимает на вход экземпляр очереди, с которой предстоит производить манипуляции,
 * и сохраняет его во внутреннее свойство _queue.
 */
QueueUI::QueueUI(IQueue* queue) {
_queue = queue;
}

/**
 * Выводит список доступных команд
 */
void QueueUI::_printHelp() {
    cout << "Available commands:" << endl << endl;
    cout << "put      Put number to queue" << endl;
    cout << "get      Pop number from queue" << endl;
    cout << "dump     Dump current queue" << endl;
    cout << "clear    Clear queue" << endl;
    cout << "help     Print help" << endl;
    cout << "exit     Exit (or press Ctrl-C)" << endl << endl;
};

/**
 * Запрашивает ввод числа пользователем и возвращает это число. Если пользователь
 * ввёл не число, то выводит сообщение об ошибке и снова запрашивает число. Так
 * продолжается до тех пор, пока пользователь наконец не введёт число.
 */
int QueueUI::_inputNumber() {
    int number;
    do {
        cout << "Number: ";
        cin >> number;
        if (cin.fail()) {
            cerr << "Invalid input, try again." << endl;
            cin.clear();
            cin.sync();
        } else {
            break;
        }
    } while (true);
    return number;
}

/**
 * Основной жизненный цикл: опрос ввода с клавиатуры, выполнение команд, вывод результатов
 */
void QueueUI::lifecycle() {
    // В начале жизненного цикла неплохо вывести пользователю подсказку по доступным командам
    _printHelp();

    // Бесконечный цикл получения и обработки команд от пользователя
    while (true) {
        string cmd;
        cout << "Enter command: ";
        cin >> cmd;

        try {
            // Команда "put"
            if (cmd == "put") {
                _queue->put(_inputNumber());
                continue;
            }

            // Команда "get"
            if (cmd == "get") {
                int number = _queue->get();
                cout << "Next number is: " << number << endl;
                continue;
            }

            // Команда "dump"
            if (cmd == "dump") {
                if (! _queue->isEmpty()) {
                    int counter = 1;
                    _queue->reset();
                    while (_queue->moveNext()) {
                        cout << counter << ": " << _queue->current() << endl;
                        counter++;
                    }
                } else {
                    cout << "There's no items in the queue" << endl;
                }
                continue;
            }

            // Команда "clear"
            if (cmd == "clear") {
                _queue->clear();
                cout << "The queue has been cleared" << endl;
                continue;
            }

            // Команда "help"
            if (cmd == "help") {
                _printHelp();
                continue;
            }

            // Команда "exit"
            if (cmd == "exit") {
                break;
            }

            // Если мы дошли до сюда -- значит ввод не распознан как известная команда
            throw runtime_error("Unrecognized command \"" + cmd + "\"");
        } catch (exception& e) {
            // Если возникло исключение -- выводим текст исключения в stderr
            cerr << "ERROR: " << e.what() << endl;
        }
    }
}
<commit_msg>Добавлен #include <string> и убран префикс "c++/" у инклуда с "stdexcept"<commit_after>#include <iostream>
#include <stdexcept>
#include <string>
#include "queue_ui.h"

using namespace std;

/**
 * Конструктор. Принимает на вход экземпляр очереди, с которой предстоит производить манипуляции,
 * и сохраняет его во внутреннее свойство _queue.
 */
QueueUI::QueueUI(IQueue* queue) {
_queue = queue;
}

/**
 * Выводит список доступных команд
 */
void QueueUI::_printHelp() {
    cout << "Available commands:" << endl << endl;
    cout << "put      Put number to queue" << endl;
    cout << "get      Pop number from queue" << endl;
    cout << "dump     Dump current queue" << endl;
    cout << "clear    Clear queue" << endl;
    cout << "help     Print help" << endl;
    cout << "exit     Exit (or press Ctrl-C)" << endl << endl;
};

/**
 * Запрашивает ввод числа пользователем и возвращает это число. Если пользователь
 * ввёл не число, то выводит сообщение об ошибке и снова запрашивает число. Так
 * продолжается до тех пор, пока пользователь наконец не введёт число.
 */
int QueueUI::_inputNumber() {
    int number;
    do {
        cout << "Number: ";
        cin >> number;
        if (cin.fail()) {
            cerr << "Invalid input, try again." << endl;
            cin.clear();
            cin.sync();
        } else {
            break;
        }
    } while (true);
    return number;
}

/**
 * Основной жизненный цикл: опрос ввода с клавиатуры, выполнение команд, вывод результатов
 */
void QueueUI::lifecycle() {
    // В начале жизненного цикла неплохо вывести пользователю подсказку по доступным командам
    _printHelp();

    // Бесконечный цикл получения и обработки команд от пользователя
    while (true) {
        string cmd;
        cout << "Enter command: ";
        cin >> cmd;

        try {
            // Команда "put"
            if (cmd == "put") {
                _queue->put(_inputNumber());
                continue;
            }

            // Команда "get"
            if (cmd == "get") {
                int number = _queue->get();
                cout << "Next number is: " << number << endl;
                continue;
            }

            // Команда "dump"
            if (cmd == "dump") {
                if (! _queue->isEmpty()) {
                    int counter = 1;
                    _queue->reset();
                    while (_queue->moveNext()) {
                        cout << counter << ": " << _queue->current() << endl;
                        counter++;
                    }
                } else {
                    cout << "There's no items in the queue" << endl;
                }
                continue;
            }

            // Команда "clear"
            if (cmd == "clear") {
                _queue->clear();
                cout << "The queue has been cleared" << endl;
                continue;
            }

            // Команда "help"
            if (cmd == "help") {
                _printHelp();
                continue;
            }

            // Команда "exit"
            if (cmd == "exit") {
                break;
            }

            // Если мы дошли до сюда -- значит ввод не распознан как известная команда
            throw runtime_error("Unrecognized command \"" + cmd + "\"");
        } catch (exception& e) {
            // Если возникло исключение -- выводим текст исключения в stderr
            cerr << "ERROR: " << e.what() << endl;
        }
    }
}
<|endoftext|>


<commit_before>#ifndef _Hasher_H_
#define _Hasher_H_

#include "HashStrategy.hpp"
#include "irods_error.hpp"

#include <string>
#include <boost/any.hpp>

namespace irods {

const std::string STRICT_HASH_POLICY( "strict" );
const std::string COMPATIBLE_HASH_POLICY( "compatible" );

class Hasher {
public:

    error init( const HashStrategy* );
    error update( const std::string& );
    error digest( std::string& messageDigest );

private:
    const HashStrategy* _strategy = NULL;
    boost::any          _context;
    error               _stored_error;
    std::string         _stored_digest;
};

}; // namespace irods

#endif // _Hasher_H_
<commit_msg>[#858] Added explicit default constructor to support older compilers<commit_after>#ifndef _Hasher_H_
#define _Hasher_H_

#include "HashStrategy.hpp"
#include "irods_error.hpp"

#include <string>
#include <boost/any.hpp>

namespace irods {

const std::string STRICT_HASH_POLICY( "strict" );
const std::string COMPATIBLE_HASH_POLICY( "compatible" );

class Hasher {
public:
    Hasher() : _strategy( NULL ) {}

    error init( const HashStrategy* );
    error update( const std::string& );
    error digest( std::string& messageDigest );

private:
    const HashStrategy* _strategy;
    boost::any          _context;
    error               _stored_error;
    std::string         _stored_digest;
};

}; // namespace irods

#endif // _Hasher_H_
<|endoftext|>


<commit_before>#include "Rules/PossibleForwardDeclarationRule.h"

#include "Common/Context.h"
#include "Common/OutputPrinter.h"
#include "Common/SourceLocationHelper.h"
#include "Common/TagTypeMatchers.h"
#include "Common/TagTypeNameHelper.h"

#include <clang/AST/Decl.h>

#include <boost/format.hpp>

#include <algorithm>
#include <vector>

using namespace llvm;
using namespace clang;
using namespace clang::ast_matchers;

namespace
{

QualType RecursivelyDesugarType(const QualType& type)
{
    QualType desugaredType = type;

    while (true)
    {
        const ElaboratedType* elaboratedType = desugaredType->getAs<ElaboratedType>();
        if (elaboratedType != nullptr)
        {
            desugaredType = elaboratedType->desugar();
            continue;
        }

        if (desugaredType->isArrayType())
        {
            desugaredType = desugaredType->getAsArrayTypeUnsafe()->getElementType();
            continue;
        }

        const PointerType* pointerType = desugaredType->getAs<PointerType>();
        if (pointerType != nullptr)
        {
            desugaredType = pointerType->getPointeeType();
            continue;
        }

        const ReferenceType* referenceType = desugaredType->getAs<ReferenceType>();
        if (referenceType != nullptr)
        {
            desugaredType = referenceType->getPointeeType();
            continue;
        }

        break;
    }

    return desugaredType;
}

QualType RecursivelyDesugarTypedefType(const QualType& type)
{
    QualType desugaredType = type;
    bool haveTypedefType = false;

    while (true)
    {
        const TypedefType* typedefType = desugaredType->getAs<TypedefType>();
        if (typedefType != nullptr)
        {
            desugaredType = typedefType->desugar();
            haveTypedefType = true;
            continue;
        }

        const ElaboratedType* elaboratedType = desugaredType->getAs<ElaboratedType>();
        if (elaboratedType != nullptr)
        {
            desugaredType = elaboratedType->desugar();
            continue;
        }

        if (desugaredType->isArrayType())
        {
            desugaredType = desugaredType->getAsArrayTypeUnsafe()->getElementType();
            continue;
        }

        const PointerType* pointerType = desugaredType->getAs<PointerType>();
        if (pointerType != nullptr)
        {
            desugaredType = pointerType->getPointeeType();
            continue;
        }

        const ReferenceType* referenceType = desugaredType->getAs<ReferenceType>();
        if (referenceType != nullptr)
        {
            desugaredType = referenceType->getPointeeType();
            continue;
        }

        break;
    }

    if (!haveTypedefType)
    {
        return QualType();
    }

    return desugaredType;
}

} // anonymous namespace

namespace clang
{
namespace ast_matchers
{

AST_MATCHER_P(QualType, recursivelyDesugaredType, internal::Matcher<QualType>, InnerMatcher)
{
    if (Node.isNull())
        return false;

    QualType desugaredType = RecursivelyDesugarType(Node);
    return InnerMatcher.matches(desugaredType, Finder, Builder);
}

AST_MATCHER_P(QualType, recursivelyDesugaredTypedefType, internal::Matcher<QualType>, InnerMatcher)
{
    if (Node.isNull())
        return false;

    QualType desugaredType = RecursivelyDesugarTypedefType(Node);
    return InnerMatcher.matches(desugaredType, Finder, Builder);
}

AST_MATCHER_P(QualType, pointerOrReferenceTypeTo, internal::Matcher<QualType>, InnerMatcher)
{
    if (Node.isNull())
        return false;

    const PointerType* pointerType = Node->getAs<PointerType>();
    if (pointerType != nullptr)
    {
        return InnerMatcher.matches(pointerType->getPointeeType(), Finder, Builder);
    }

    const ReferenceType* referenceType = Node->getAs<ReferenceType>();
    if (referenceType != nullptr)
    {
        return InnerMatcher.matches(referenceType->getPointeeType(), Finder, Builder);
    }

    return false;
}

AST_MATCHER(TagDecl, isForwardDeclaration)
{
    return Node.getDefinition() == nullptr;
}

AST_MATCHER(EnumDecl, isScopedUsingClassTag)
{
    return Node.isScopedUsingClassTag();
}

} // namespace ast_matchers
} // namespace clang

internal::Matcher<QualType> CreateActualTagTypeMatcher()
{
    return qualType(hasDeclaration(tagDecl(
        unless(isExpansionInSystemHeader()),
        anyOf(classTemplateSpecializationDecl().bind("classTemplate"),
              enumDecl(unless(isScopedUsingClassTag())).bind("oldStyleEnum"),
              tagDecl(isForwardDeclaration()).bind("existingForwardDeclaration"),
              anything()))
           .bind("tagDecl")));
}

internal::Matcher<QualType> CreateTemplateTagTypeMatcher()
{
    return templateSpecializationType(
        hasAnyTemplateArgument(
            refersToType(
                recursivelyDesugaredType(CreateActualTagTypeMatcher()))));
}

internal::Matcher<QualType> CreateTagTypeMatcher()
{
    return anyOf(qualType(recursivelyDesugaredTypedefType(CreateTemplateTagTypeMatcher())),
                 qualType(recursivelyDesugaredTypedefType(CreateActualTagTypeMatcher())),
                 qualType(recursivelyDesugaredType(CreateTemplateTagTypeMatcher())),
                 qualType(pointerOrReferenceTypeTo(recursivelyDesugaredType(CreateActualTagTypeMatcher()))).bind("ptrOrRefType"),
                 qualType(recursivelyDesugaredType(CreateActualTagTypeMatcher())));
}

PossibleForwardDeclarationRule::PossibleForwardDeclarationRule(Context& context)
    : Rule(context)
{}

void PossibleForwardDeclarationRule::RegisterASTMatcherCallback(MatchFinder& finder)
{
    finder.addMatcher(recordDecl().bind("recordDecl"), this);
    finder.addMatcher(declRefExpr().bind("declRefExpr"), this);
    finder.addMatcher(
        decl(anyOf(valueDecl(hasType(CreateTagTypeMatcher())),
                   functionDecl(returns(CreateTagTypeMatcher())))).bind("declWithTagType"),
        this);
    finder.addMatcher(expr(hasType(CreateTagTypeMatcher())).bind("exprWithTagType"), this);
}

void PossibleForwardDeclarationRule::run(const MatchFinder::MatchResult& result)
{
    m_sourceManager = result.SourceManager;

    const DeclRefExpr* declarationReferenceExpression = result.Nodes.getNodeAs<DeclRefExpr>("declRefExpr");
    if (declarationReferenceExpression != nullptr)
        return HandleDeclarationReferenceExpression(declarationReferenceExpression);

    const CXXRecordDecl* recordDeclaration = result.Nodes.getNodeAs<CXXRecordDecl>("recordDecl");
    if (recordDeclaration != nullptr)
        return HandleRecordDeclaration(recordDeclaration);

    const TagDecl* tagDeclaration = result.Nodes.getNodeAs<TagDecl>("tagDecl");
    if (tagDeclaration == nullptr)
        return;

    if (IsInBlacklistedProjectHeader(tagDeclaration))
        return; // already blacklisted, so no point of checking further

    if (! IsInDirectlyIncludedProjectHeader(tagDeclaration))
        return;

    bool isExistingForwardDeclaration = result.Nodes.getNodeAs<Decl>("existingForwardDeclaration") != nullptr;
    if (isExistingForwardDeclaration)
        return;

    tagDeclaration = tagDeclaration->getCanonicalDecl();

    bool isPointerOrReferenceType = result.Nodes.getNodeAs<QualType>("ptrOrRefType") != nullptr;
    bool isTemplateClassType = result.Nodes.getNodeAs<Decl>("classTemplate") != nullptr;
    bool isOldStyleEnum = result.Nodes.getNodeAs<Decl>("oldStyleEnum") != nullptr;

    const Decl* declarationWithTagType = result.Nodes.getNodeAs<Decl>("declWithTagType");
    if (declarationWithTagType != nullptr)
        return HandleDeclarationWithTagType(tagDeclaration,
                                            declarationWithTagType,
                                            isPointerOrReferenceType,
                                            isTemplateClassType,
                                            isOldStyleEnum);

    const Expr* expressionWithTagType = result.Nodes.getNodeAs<Expr>("exprWithTagType");
    if (expressionWithTagType != nullptr)
        return HandleExpressionWithTagType(tagDeclaration, expressionWithTagType);
}

bool PossibleForwardDeclarationRule::IsInBlacklistedProjectHeader(const Decl* declaration)
{
    FileID tagDeclarationFileID = m_sourceManager->getFileID(declaration->getLocation());
    bool result = m_blacklistedProjectHeaders.count(tagDeclarationFileID) > 0;
    return result;
}

void PossibleForwardDeclarationRule::BlacklistIncludedProjectHeader(const Decl* declaration)
{
    FileID tagDeclarationFileID = m_sourceManager->getFileID(declaration->getLocation());
    m_blacklistedProjectHeaders.insert(tagDeclarationFileID);
}
bool PossibleForwardDeclarationRule::IsInDirectlyIncludedProjectHeader(const Decl* declaration)
{
    SourceLocation tagDeclarationLocation = declaration->getLocation();
    if (! m_context.sourceLocationHelper.IsLocationInProjectSourceFile(tagDeclarationLocation, *m_sourceManager))
        return false;

    FileID tagDeclarationFileID = m_sourceManager->getFileID(declaration->getLocation());
    if (tagDeclarationFileID.isInvalid())
        return false;

    SourceLocation tagDeclarationIncludeLocation = m_sourceManager->getIncludeLoc(tagDeclarationFileID);
    if (tagDeclarationIncludeLocation.isInvalid())
        return false;

    FileID tagDeclarationIncludeFileID = m_sourceManager->getFileID(tagDeclarationIncludeLocation);
    if (tagDeclarationIncludeFileID.isInvalid())
        return false;

    FileID mainFileID = m_context.sourceLocationHelper.GetMainFileID(*m_sourceManager);
    if (mainFileID.isInvalid())
        return false;

    // we want declaration from directly included project header (no indirect dependencies)
    return tagDeclarationFileID != mainFileID && tagDeclarationIncludeFileID == mainFileID;
}

void PossibleForwardDeclarationRule::HandleDeclarationReferenceExpression(const DeclRefExpr* declarationReferenceExpression)
{
    SourceLocation location = declarationReferenceExpression->getLocation();
    if (! m_context.sourceLocationHelper.IsLocationOfInterest(GetName(), location, *m_sourceManager))
        return;

    const Decl* declaration = declarationReferenceExpression->getDecl();
    if (IsInDirectlyIncludedProjectHeader(declaration))
    {
        BlacklistIncludedProjectHeader(declaration);
    }
}

void PossibleForwardDeclarationRule::HandleRecordDeclaration(const CXXRecordDecl* recordDeclaration)
{
    SourceLocation location = recordDeclaration->getLocation();
    if (! m_context.sourceLocationHelper.IsLocationOfInterest(GetName(), location, *m_sourceManager))
        return;

    const CXXRecordDecl* recordDefinition = recordDeclaration->getDefinition();
    if (recordDefinition == nullptr)
        return;

    for (const auto& base : recordDefinition->bases())
    {
        const RecordType* baseRecordType = base.getType()->getAs<RecordType>();
        if (baseRecordType == nullptr)
            continue;

        const RecordDecl* baseDeclaration = baseRecordType->getDecl();
        if (baseDeclaration == nullptr)
            continue;

        const RecordDecl* baseDefinition = baseDeclaration->getDefinition();
        if (baseDefinition == nullptr)
            continue;

        if (IsInDirectlyIncludedProjectHeader(baseDefinition))
        {
            BlacklistIncludedProjectHeader(baseDefinition);
        }
    }
}

void PossibleForwardDeclarationRule::HandleDeclarationWithTagType(const TagDecl* tagDeclaration,
                                                                  const Decl* declarationWithTagType,
                                                                  bool isPointerOrReferenceType,
                                                                  bool isTemplateClassType,
                                                                  bool isOldStyleEnum)
{
    SourceLocation location = declarationWithTagType->getLocation();
    if (! m_context.sourceLocationHelper.IsLocationOfInterest(GetName(), location, *m_sourceManager))
        return;

    if (isPointerOrReferenceType &&
        !isTemplateClassType &&
        !isOldStyleEnum &&
        (isa<ParmVarDecl>(declarationWithTagType) ||
         isa<FieldDecl>(declarationWithTagType) ||
         isa<FunctionDecl>(declarationWithTagType)))
    {
        if (m_candidateForwardDeclarations.count(tagDeclaration) == 0)
        {
            m_candidateForwardDeclarations.insert(std::make_pair(tagDeclaration, location));
        }
    }
    else
    {
        m_candidateForwardDeclarations.erase(tagDeclaration);
        BlacklistIncludedProjectHeader(tagDeclaration);
    }
}

void PossibleForwardDeclarationRule::HandleExpressionWithTagType(const TagDecl* tagDeclaration,
                                                                 const Expr* expressionWithTagType)
{
    SourceLocation location = expressionWithTagType->getLocStart();
    if (! m_context.sourceLocationHelper.IsLocationOfInterest(GetName(), location, *m_sourceManager))
        return;

    m_candidateForwardDeclarations.erase(tagDeclaration);
    BlacklistIncludedProjectHeader(tagDeclaration);
}

void PossibleForwardDeclarationRule::onEndOfTranslationUnit()
{
    using DeclarationInfoPair = std::pair<const TagDecl*, SourceLocation>;
    std::vector<DeclarationInfoPair> forwardDeclarations;
    for (const DeclarationInfoPair& forwardDeclaration : m_candidateForwardDeclarations)
    {
        if (! IsInBlacklistedProjectHeader(forwardDeclaration.first))
        {
            forwardDeclarations.push_back(forwardDeclaration);
        }
    }

    std::sort(forwardDeclarations.begin(),
              forwardDeclarations.end(),
              [this](const DeclarationInfoPair& left, const DeclarationInfoPair& right)
              {
                  return m_sourceManager->isBeforeInTranslationUnit(left.second, right.second);
              });

    for (const DeclarationInfoPair& forwardDeclaration : forwardDeclarations)
    {
        m_context.outputPrinter->PrintRuleViolation(
            "possible forward declaration",
            Severity::Information,
            boost::str(boost::format("%s '%s' can be forward declared instead of #included")
                % GetTagTypeString(forwardDeclaration.first)
                % forwardDeclaration.first->getQualifiedNameAsString()),
            forwardDeclaration.second,
            *m_sourceManager);
    }

    m_candidateForwardDeclarations.clear();
}
<commit_msg>Fix for runtime assert in debug builds<commit_after>#include "Rules/PossibleForwardDeclarationRule.h"

#include "Common/Context.h"
#include "Common/OutputPrinter.h"
#include "Common/SourceLocationHelper.h"
#include "Common/TagTypeMatchers.h"
#include "Common/TagTypeNameHelper.h"

#include <clang/AST/Decl.h>

#include <boost/format.hpp>

#include <algorithm>
#include <vector>

using namespace llvm;
using namespace clang;
using namespace clang::ast_matchers;

namespace
{

QualType RecursivelyDesugarType(const QualType& type)
{
    QualType desugaredType = type;

    while (true)
    {
        const ElaboratedType* elaboratedType = desugaredType->getAs<ElaboratedType>();
        if (elaboratedType != nullptr)
        {
            desugaredType = elaboratedType->desugar();
            continue;
        }

        if (desugaredType->isArrayType())
        {
            desugaredType = desugaredType->getAsArrayTypeUnsafe()->getElementType();
            continue;
        }

        const PointerType* pointerType = desugaredType->getAs<PointerType>();
        if (pointerType != nullptr)
        {
            desugaredType = pointerType->getPointeeType();
            continue;
        }

        const ReferenceType* referenceType = desugaredType->getAs<ReferenceType>();
        if (referenceType != nullptr)
        {
            desugaredType = referenceType->getPointeeType();
            continue;
        }

        break;
    }

    return desugaredType;
}

QualType RecursivelyDesugarTypedefType(const QualType& type)
{
    QualType desugaredType = type;
    bool haveTypedefType = false;

    while (true)
    {
        const TypedefType* typedefType = desugaredType->getAs<TypedefType>();
        if (typedefType != nullptr)
        {
            desugaredType = typedefType->desugar();
            haveTypedefType = true;
            continue;
        }

        const ElaboratedType* elaboratedType = desugaredType->getAs<ElaboratedType>();
        if (elaboratedType != nullptr)
        {
            desugaredType = elaboratedType->desugar();
            continue;
        }

        if (desugaredType->isArrayType())
        {
            desugaredType = desugaredType->getAsArrayTypeUnsafe()->getElementType();
            continue;
        }

        const PointerType* pointerType = desugaredType->getAs<PointerType>();
        if (pointerType != nullptr)
        {
            desugaredType = pointerType->getPointeeType();
            continue;
        }

        const ReferenceType* referenceType = desugaredType->getAs<ReferenceType>();
        if (referenceType != nullptr)
        {
            desugaredType = referenceType->getPointeeType();
            continue;
        }

        break;
    }

    if (!haveTypedefType)
    {
        return QualType();
    }

    return desugaredType;
}

} // anonymous namespace

namespace clang
{
namespace ast_matchers
{

AST_MATCHER_P(QualType, recursivelyDesugaredType, internal::Matcher<QualType>, InnerMatcher)
{
    if (Node.isNull())
        return false;

    QualType desugaredType = RecursivelyDesugarType(Node);
    return InnerMatcher.matches(desugaredType, Finder, Builder);
}

AST_MATCHER_P(QualType, recursivelyDesugaredTypedefType, internal::Matcher<QualType>, InnerMatcher)
{
    if (Node.isNull())
        return false;

    QualType desugaredType = RecursivelyDesugarTypedefType(Node);
    return InnerMatcher.matches(desugaredType, Finder, Builder);
}

AST_MATCHER_P(QualType, pointerOrReferenceTypeTo, internal::Matcher<QualType>, InnerMatcher)
{
    if (Node.isNull())
        return false;

    const PointerType* pointerType = Node->getAs<PointerType>();
    if (pointerType != nullptr)
    {
        return InnerMatcher.matches(pointerType->getPointeeType(), Finder, Builder);
    }

    const ReferenceType* referenceType = Node->getAs<ReferenceType>();
    if (referenceType != nullptr)
    {
        return InnerMatcher.matches(referenceType->getPointeeType(), Finder, Builder);
    }

    return false;
}

AST_MATCHER(TagDecl, isForwardDeclaration)
{
    return Node.getDefinition() == nullptr;
}

AST_MATCHER(EnumDecl, isScopedUsingClassTag)
{
    return Node.isScopedUsingClassTag();
}

} // namespace ast_matchers
} // namespace clang

internal::Matcher<QualType> CreateActualTagTypeMatcher()
{
    return qualType(hasDeclaration(tagDecl(
        unless(isExpansionInSystemHeader()),
        anyOf(classTemplateSpecializationDecl().bind("classTemplate"),
              enumDecl(unless(isScopedUsingClassTag())).bind("oldStyleEnum"),
              tagDecl(isForwardDeclaration()).bind("existingForwardDeclaration"),
              anything()))
           .bind("tagDecl")));
}

internal::Matcher<QualType> CreateTemplateTagTypeMatcher()
{
    return templateSpecializationType(
        hasAnyTemplateArgument(
            refersToType(
                recursivelyDesugaredType(CreateActualTagTypeMatcher()))));
}

internal::Matcher<QualType> CreateTagTypeMatcher()
{
    return anyOf(qualType(recursivelyDesugaredTypedefType(CreateTemplateTagTypeMatcher())),
                 qualType(recursivelyDesugaredTypedefType(CreateActualTagTypeMatcher())),
                 qualType(recursivelyDesugaredType(CreateTemplateTagTypeMatcher())),
                 qualType(pointerOrReferenceTypeTo(recursivelyDesugaredType(CreateActualTagTypeMatcher()))).bind("ptrOrRefType"),
                 qualType(recursivelyDesugaredType(CreateActualTagTypeMatcher())));
}

PossibleForwardDeclarationRule::PossibleForwardDeclarationRule(Context& context)
    : Rule(context)
{}

void PossibleForwardDeclarationRule::RegisterASTMatcherCallback(MatchFinder& finder)
{
    finder.addMatcher(recordDecl().bind("recordDecl"), this);
    finder.addMatcher(declRefExpr().bind("declRefExpr"), this);
    finder.addMatcher(
        decl(anyOf(valueDecl(hasType(CreateTagTypeMatcher())),
                   functionDecl(returns(CreateTagTypeMatcher())))).bind("declWithTagType"),
        this);
    finder.addMatcher(expr(hasType(CreateTagTypeMatcher())).bind("exprWithTagType"), this);
}

void PossibleForwardDeclarationRule::run(const MatchFinder::MatchResult& result)
{
    m_sourceManager = result.SourceManager;

    const DeclRefExpr* declarationReferenceExpression = result.Nodes.getNodeAs<DeclRefExpr>("declRefExpr");
    if (declarationReferenceExpression != nullptr)
        return HandleDeclarationReferenceExpression(declarationReferenceExpression);

    const CXXRecordDecl* recordDeclaration = result.Nodes.getNodeAs<CXXRecordDecl>("recordDecl");
    if (recordDeclaration != nullptr)
        return HandleRecordDeclaration(recordDeclaration);

    const TagDecl* tagDeclaration = result.Nodes.getNodeAs<TagDecl>("tagDecl");
    if (tagDeclaration == nullptr)
        return;

    if (IsInBlacklistedProjectHeader(tagDeclaration))
        return; // already blacklisted, so no point of checking further

    if (! IsInDirectlyIncludedProjectHeader(tagDeclaration))
        return;

    bool isExistingForwardDeclaration = result.Nodes.getNodeAs<Decl>("existingForwardDeclaration") != nullptr;
    if (isExistingForwardDeclaration)
        return;

    tagDeclaration = tagDeclaration->getCanonicalDecl();

    bool isPointerOrReferenceType = result.Nodes.getNodeAs<QualType>("ptrOrRefType") != nullptr;
    bool isTemplateClassType = result.Nodes.getNodeAs<Decl>("classTemplate") != nullptr;
    bool isOldStyleEnum = result.Nodes.getNodeAs<Decl>("oldStyleEnum") != nullptr;

    const Decl* declarationWithTagType = result.Nodes.getNodeAs<Decl>("declWithTagType");
    if (declarationWithTagType != nullptr)
        return HandleDeclarationWithTagType(tagDeclaration,
                                            declarationWithTagType,
                                            isPointerOrReferenceType,
                                            isTemplateClassType,
                                            isOldStyleEnum);

    const Expr* expressionWithTagType = result.Nodes.getNodeAs<Expr>("exprWithTagType");
    if (expressionWithTagType != nullptr)
        return HandleExpressionWithTagType(tagDeclaration, expressionWithTagType);
}

bool PossibleForwardDeclarationRule::IsInBlacklistedProjectHeader(const Decl* declaration)
{
    FileID tagDeclarationFileID = m_sourceManager->getFileID(declaration->getLocation());
    return !tagDeclarationFileID.isInvalid() && m_blacklistedProjectHeaders.count(tagDeclarationFileID) > 0;
}

void PossibleForwardDeclarationRule::BlacklistIncludedProjectHeader(const Decl* declaration)
{
    FileID tagDeclarationFileID = m_sourceManager->getFileID(declaration->getLocation());
    m_blacklistedProjectHeaders.insert(tagDeclarationFileID);
}
bool PossibleForwardDeclarationRule::IsInDirectlyIncludedProjectHeader(const Decl* declaration)
{
    SourceLocation tagDeclarationLocation = declaration->getLocation();
    if (! m_context.sourceLocationHelper.IsLocationInProjectSourceFile(tagDeclarationLocation, *m_sourceManager))
        return false;

    FileID tagDeclarationFileID = m_sourceManager->getFileID(declaration->getLocation());
    if (tagDeclarationFileID.isInvalid())
        return false;

    SourceLocation tagDeclarationIncludeLocation = m_sourceManager->getIncludeLoc(tagDeclarationFileID);
    if (tagDeclarationIncludeLocation.isInvalid())
        return false;

    FileID tagDeclarationIncludeFileID = m_sourceManager->getFileID(tagDeclarationIncludeLocation);
    if (tagDeclarationIncludeFileID.isInvalid())
        return false;

    FileID mainFileID = m_context.sourceLocationHelper.GetMainFileID(*m_sourceManager);
    if (mainFileID.isInvalid())
        return false;

    // we want declaration from directly included project header (no indirect dependencies)
    return tagDeclarationFileID != mainFileID && tagDeclarationIncludeFileID == mainFileID;
}

void PossibleForwardDeclarationRule::HandleDeclarationReferenceExpression(const DeclRefExpr* declarationReferenceExpression)
{
    SourceLocation location = declarationReferenceExpression->getLocation();
    if (! m_context.sourceLocationHelper.IsLocationOfInterest(GetName(), location, *m_sourceManager))
        return;

    const Decl* declaration = declarationReferenceExpression->getDecl();
    if (IsInDirectlyIncludedProjectHeader(declaration))
    {
        BlacklistIncludedProjectHeader(declaration);
    }
}

void PossibleForwardDeclarationRule::HandleRecordDeclaration(const CXXRecordDecl* recordDeclaration)
{
    SourceLocation location = recordDeclaration->getLocation();
    if (! m_context.sourceLocationHelper.IsLocationOfInterest(GetName(), location, *m_sourceManager))
        return;

    const CXXRecordDecl* recordDefinition = recordDeclaration->getDefinition();
    if (recordDefinition == nullptr)
        return;

    for (const auto& base : recordDefinition->bases())
    {
        const RecordType* baseRecordType = base.getType()->getAs<RecordType>();
        if (baseRecordType == nullptr)
            continue;

        const RecordDecl* baseDeclaration = baseRecordType->getDecl();
        if (baseDeclaration == nullptr)
            continue;

        const RecordDecl* baseDefinition = baseDeclaration->getDefinition();
        if (baseDefinition == nullptr)
            continue;

        if (IsInDirectlyIncludedProjectHeader(baseDefinition))
        {
            BlacklistIncludedProjectHeader(baseDefinition);
        }
    }
}

void PossibleForwardDeclarationRule::HandleDeclarationWithTagType(const TagDecl* tagDeclaration,
                                                                  const Decl* declarationWithTagType,
                                                                  bool isPointerOrReferenceType,
                                                                  bool isTemplateClassType,
                                                                  bool isOldStyleEnum)
{
    SourceLocation location = declarationWithTagType->getLocation();
    if (! m_context.sourceLocationHelper.IsLocationOfInterest(GetName(), location, *m_sourceManager))
        return;

    if (isPointerOrReferenceType &&
        !isTemplateClassType &&
        !isOldStyleEnum &&
        (isa<ParmVarDecl>(declarationWithTagType) ||
         isa<FieldDecl>(declarationWithTagType) ||
         isa<FunctionDecl>(declarationWithTagType)))
    {
        if (m_candidateForwardDeclarations.count(tagDeclaration) == 0)
        {
            m_candidateForwardDeclarations.insert(std::make_pair(tagDeclaration, location));
        }
    }
    else
    {
        m_candidateForwardDeclarations.erase(tagDeclaration);
        BlacklistIncludedProjectHeader(tagDeclaration);
    }
}

void PossibleForwardDeclarationRule::HandleExpressionWithTagType(const TagDecl* tagDeclaration,
                                                                 const Expr* expressionWithTagType)
{
    SourceLocation location = expressionWithTagType->getLocStart();
    if (! m_context.sourceLocationHelper.IsLocationOfInterest(GetName(), location, *m_sourceManager))
        return;

    m_candidateForwardDeclarations.erase(tagDeclaration);
    BlacklistIncludedProjectHeader(tagDeclaration);
}

void PossibleForwardDeclarationRule::onEndOfTranslationUnit()
{
    using DeclarationInfoPair = std::pair<const TagDecl*, SourceLocation>;
    std::vector<DeclarationInfoPair> forwardDeclarations;
    for (const DeclarationInfoPair& forwardDeclaration : m_candidateForwardDeclarations)
    {
        if (! IsInBlacklistedProjectHeader(forwardDeclaration.first))
        {
            forwardDeclarations.push_back(forwardDeclaration);
        }
    }

    std::sort(forwardDeclarations.begin(),
              forwardDeclarations.end(),
              [this](const DeclarationInfoPair& left, const DeclarationInfoPair& right)
              {
                  return m_sourceManager->isBeforeInTranslationUnit(left.second, right.second);
              });

    for (const DeclarationInfoPair& forwardDeclaration : forwardDeclarations)
    {
        m_context.outputPrinter->PrintRuleViolation(
            "possible forward declaration",
            Severity::Information,
            boost::str(boost::format("%s '%s' can be forward declared instead of #included")
                % GetTagTypeString(forwardDeclaration.first)
                % forwardDeclaration.first->getQualifiedNameAsString()),
            forwardDeclaration.second,
            *m_sourceManager);
    }

    m_candidateForwardDeclarations.clear();
}
<|endoftext|>


<commit_before><commit_msg>Hacky workaround for asymmetric fov issue<commit_after><|endoftext|>