<commit_before>#include "detectors.h"

//Constructor vacio
Detectors::Detectors(void)
{
	this->hog = HOGDescriptor();
}

//Constructores
Detectors::Detectors(HOGDescriptor hog_)
{
	this->hog = HOGDescriptor(hog_);
}

//Constructor Copia
Detectors::Detectors(const Detectors& Detectors_)
{
	this->hog = Detectors_.hog;
}

//Load SVM
void Detectors::LoadSVM(string svm_model)
{
	this->SVM.load(svm_model.c_str());
}

//Load Adaboost
void Detectors::LoadAdaboost(string boost_model)
{
	this->boost.load(boost_model.c_str());
}

//Deteccion con HOG + SVM unitaria
Mat Detectors::HOGSVMDetectShow(string filename)
{
	Mat img;
	img = imread(filename);
	if(!img.data)
		return img;
	vector<float> descriptor_result;
	for (int x = 3; x < (img.cols-3-hog.winSize.width); x++)
	{
		for (int y = 3; y < (img.rows-3-hog.winSize.height); y++)
		{
			Rect roi(x,y,hog.winSize.width,hog.winSize.height);
			Mat crop = img(roi);
			hog.compute(crop,descriptor_result);
			Mat crop_hog = Mat(1,descriptor_result.size(),CV_32FC1);
			for (int i = 0; i < descriptor_result.size(); i++)
			{
				crop_hog.at<float>(0,i) = descriptor_result[i];
			}

			float result = SVM.predict(crop_hog,true);

			Point ce = Point((roi.tl().x+roi.br().x)/2,(roi.tl().y+roi.br().y)/2);
			line( img, ce,ce, Scalar(0, 0, 255*result),1,8);
			//rectangle(img, roi.tl(), roi.br(), cv::Scalar(0,255*result,0), 1);
		}
	}
	return img;
}
//Deteccion con HOG + SVM unitaria
Mat Detectors::HOGSVMDetectShow(string filename, string svm_model)
{
	this->SVM.load(svm_model.c_str());
	return HOGSVMDetectShow(filename);
}
//
NeighbourhoodMatrix Detectors::HOGSVMDetectPrint(string filename, Sigmoid sig)
{
	Mat img;
	img = imread(filename);
	NeighbourhoodMatrix null_matrix;
	if(!img.data)
		return null_matrix;
	int rows = img.rows-6-hog.winSize.height;
	int cols = img.cols-6-hog.winSize.width;
	vector<vector<double>> matrix =  vector<vector<double>>(rows, vector<double>(cols,0.0));
	#pragma omp parallel num_threads(20)
	{
		vector<float> descriptor_result;
		#pragma omp for schedule(dynamic,rows/40)
		for (int x = 3; x < (img.cols-3-hog.winSize.width); x++)
		{

			for (int y = 3; y < (img.rows-3-hog.winSize.height); y++)
			{
				Rect roi(x,y,hog.winSize.width,hog.winSize.height);
				Mat crop = img(roi);
				hog.compute(crop,descriptor_result);
				Mat crop_hog = Mat(1,descriptor_result.size(),CV_32FC1);
				for (int i = 0; i < descriptor_result.size(); i++)
				{
					crop_hog.at<float>(0,i) = descriptor_result[i];
				}
				float result = sig.EvaluateSigmoid(SVM.predict(crop_hog,true));
				#pragma omp critical
				matrix[y-3][x-3] = (double)result;
			}
		}
	}
	NeighbourhoodMatrix neighbourhood_matrix(matrix);

	return neighbourhood_matrix;

}
NeighbourhoodMatrix Detectors::HOGSVMDetectPrint(string filename, string svm_model, Sigmoid sig)
{
	this->SVM.load(svm_model.c_str());
	return HOGSVMDetectPrint(filename, sig);
}
//Deteccion con SVM bucle
void Detectors::HOGSVMDetectBucleShow(string img_filename_list)
{
	ifstream img_filename(img_filename_list);
	string img_filename_line;
	Mat img;
	namedWindow("People Detector", 1);
	while(getline(img_filename, img_filename_line)) {

		img = HOGSVMDetectShow(img_filename_line);

		imshow("People Detector", img);

		int c = waitKey(0) & 255;
		if( c == 'q' || c == 'Q')
			break;
	}
}
void Detectors::HOGSVMDetectBuclePrint(string img_filename_list, string folder, Sigmoid sig)
{
	ifstream img_filename(img_filename_list);
	string img_filename_line;
	while(getline(img_filename, img_filename_line)) {
		NeighbourhoodMatrix neighbourhood_matrix(HOGSVMDetectPrint(img_filename_line, sig));
		img_filename_line.erase(img_filename_line.find_last_of("."), string::npos);
		img_filename_line.erase(0,img_filename_line.find_last_of("/")+1);
		string file = folder+img_filename_line+boost::lexical_cast<string>(".mat");
		neighbourhood_matrix.WriteNeigbourhoodMatrix(file);
		cout << file << endl;
	}

}
//Deteccion con HOG + Adaboost unitaria
Mat Detectors::HOGAdaboostDetectShow(string filename)
{
	Mat img;
	img = imread(filename);
	if(!img.data)
		return img;
	vector<float> descriptor_result;
	for (int x = 3; x < (img.cols-3-hog.winSize.width); x++)
	{
		for (int y = 3; y < (img.rows-3-hog.winSize.height); y++)
		{
			Rect roi(x,y,hog.winSize.width,hog.winSize.height);
			Mat crop = img(roi);
			hog.compute(crop,descriptor_result);
			Mat crop_hog = Mat(1,descriptor_result.size(),CV_32FC1);
			for (int i = 0; i < descriptor_result.size(); i++)
			{
				crop_hog.at<float>(0,i) = descriptor_result[i];
			}

			float result = boost.predict(crop_hog,Mat(),Range::all(),false,true);

			Point ce = Point((roi.tl().x+roi.br().x)/2,(roi.tl().y+roi.br().y)/2);
			line( img, ce,ce, Scalar(0, 0, 255*result),1,8);
			//rectangle(img, roi.tl(), roi.br(), cv::Scalar(0,255*result,0), 1);
		}
	}
	return img;
}
//Deteccion con HOG + SVM unitaria
Mat Detectors::HOGAdaboostDetectShow(string filename, string boost_model)
{
	this->boost.load(boost_model.c_str());
	return HOGAdaboostDetectShow(filename);
}
//
NeighbourhoodMatrix Detectors::HOGAdaboostDetectPrint(string filename, Sigmoid sig)
{
	Mat img;
	img = imread(filename);
	NeighbourhoodMatrix null_matrix;
	if(!img.data)
		return null_matrix;
	int rows = img.rows-6-hog.winSize.height;
	int cols = img.cols-6-hog.winSize.width;
	vector<vector<double>> matrix =  vector<vector<double>>(rows, vector<double>(cols,0.0));
	#pragma omp parallel num_threads(30)
	{
		vector<float> descriptor_result;
		#pragma omp for schedule(dynamic,rows/40)
		for (int x = 3; x < (img.cols-3-hog.winSize.width); x++)
		{

			for (int y = 3; y < (img.rows-3-hog.winSize.height); y++)
			{
				Rect roi(x,y,hog.winSize.width,hog.winSize.height);
				Mat crop = img(roi);
				hog.compute(crop,descriptor_result);
				Mat crop_hog = Mat(1,descriptor_result.size(),CV_32FC1);
				for (int i = 0; i < descriptor_result.size(); i++)
				{
					crop_hog.at<float>(0,i) = descriptor_result[i];
				}
				float result = sig.EvaluateSigmoid(boost.predict(crop_hog,Mat(),Range::all(),false,false));
				#pragma omp critical
				matrix[y-3][x-3] = (double)result;
			}
		}
	}
	NeighbourhoodMatrix neighbourhood_matrix(matrix);

	return neighbourhood_matrix;
}
NeighbourhoodMatrix Detectors::HOGAdaboostDetectPrint(string filename, string boost_model, Sigmoid sig)
{
	this->boost.load(boost_model.c_str());
	return HOGAdaboostDetectPrint(filename, sig);
}
//Deteccion con SVM bucle
void Detectors::HOGAdaboostDetectBucleShow(string img_filename_list)
{
	ifstream img_filename(img_filename_list);
	string img_filename_line;
	Mat img;
	namedWindow("People Detector", 1);
	while(getline(img_filename, img_filename_line)) {

		img = HOGAdaboostDetectShow(img_filename_line);

		imshow("People Detector", img);

		int c = waitKey(0) & 255;
		if( c == 'q' || c == 'Q')
			break;
	}
}
void Detectors::HOGAdaboostDetectBuclePrint(string img_filename_list,string folder, Sigmoid sig)
{
	ifstream img_filename(img_filename_list);
	string img_filename_line;
	while(getline(img_filename, img_filename_line)) {
		NeighbourhoodMatrix neighbourhood_matrix(HOGAdaboostDetectPrint(img_filename_line, sig));
		img_filename_line.erase(img_filename_line.find_last_of("."), string::npos);
		img_filename_line.erase(0,img_filename_line.find_last_of("/")+1);
		string file = folder+img_filename_line+boost::lexical_cast<string>(".mat");
		neighbourhood_matrix.WriteNeigbourhoodMatrix(file);
		cout << file << endl;
	}

}
<commit_msg>parallel<commit_after>#include "detectors.h"

//Constructor vacio
Detectors::Detectors(void)
{
	this->hog = HOGDescriptor();
}

//Constructores
Detectors::Detectors(HOGDescriptor hog_)
{
	this->hog = HOGDescriptor(hog_);
}

//Constructor Copia
Detectors::Detectors(const Detectors& Detectors_)
{
	this->hog = Detectors_.hog;
}

//Load SVM
void Detectors::LoadSVM(string svm_model)
{
	this->SVM.load(svm_model.c_str());
}

//Load Adaboost
void Detectors::LoadAdaboost(string boost_model)
{
	this->boost.load(boost_model.c_str());
}

//Deteccion con HOG + SVM unitaria
Mat Detectors::HOGSVMDetectShow(string filename)
{
	Mat img;
	img = imread(filename);
	if(!img.data)
		return img;
	vector<float> descriptor_result;
	for (int x = 3; x < (img.cols-3-hog.winSize.width); x++)
	{
		for (int y = 3; y < (img.rows-3-hog.winSize.height); y++)
		{
			Rect roi(x,y,hog.winSize.width,hog.winSize.height);
			Mat crop = img(roi);
			hog.compute(crop,descriptor_result);
			Mat crop_hog = Mat(1,descriptor_result.size(),CV_32FC1);
			for (int i = 0; i < descriptor_result.size(); i++)
			{
				crop_hog.at<float>(0,i) = descriptor_result[i];
			}

			float result = SVM.predict(crop_hog,true);

			Point ce = Point((roi.tl().x+roi.br().x)/2,(roi.tl().y+roi.br().y)/2);
			line( img, ce,ce, Scalar(0, 0, 255*result),1,8);
			//rectangle(img, roi.tl(), roi.br(), cv::Scalar(0,255*result,0), 1);
		}
	}
	return img;
}
//Deteccion con HOG + SVM unitaria
Mat Detectors::HOGSVMDetectShow(string filename, string svm_model)
{
	this->SVM.load(svm_model.c_str());
	return HOGSVMDetectShow(filename);
}
//
NeighbourhoodMatrix Detectors::HOGSVMDetectPrint(string filename, Sigmoid sig)
{
	Mat img;
	img = imread(filename);
	NeighbourhoodMatrix null_matrix;
	if(!img.data)
		return null_matrix;
	int rows = img.rows-6-hog.winSize.height;
	int cols = img.cols-6-hog.winSize.width;
	vector<vector<double>> matrix =  vector<vector<double>>(rows, vector<double>(cols,0.0));
	#pragma omp parallel num_threads(34)
	{
		vector<float> descriptor_result;
		#pragma omp for schedule(dynamic,rows/50)
		for (int x = 3; x < (img.cols-3-hog.winSize.width); x++)
		{

			for (int y = 3; y < (img.rows-3-hog.winSize.height); y++)
			{
				Rect roi(x,y,hog.winSize.width,hog.winSize.height);
				Mat crop = img(roi);
				hog.compute(crop,descriptor_result);
				Mat crop_hog = Mat(1,descriptor_result.size(),CV_32FC1);
				for (int i = 0; i < descriptor_result.size(); i++)
				{
					crop_hog.at<float>(0,i) = descriptor_result[i];
				}
				float result = sig.EvaluateSigmoid(SVM.predict(crop_hog,true));
				#pragma omp critical
				matrix[y-3][x-3] = (double)result;
			}
		}
	}
	NeighbourhoodMatrix neighbourhood_matrix(matrix);

	return neighbourhood_matrix;

}
NeighbourhoodMatrix Detectors::HOGSVMDetectPrint(string filename, string svm_model, Sigmoid sig)
{
	this->SVM.load(svm_model.c_str());
	return HOGSVMDetectPrint(filename, sig);
}
//Deteccion con SVM bucle
void Detectors::HOGSVMDetectBucleShow(string img_filename_list)
{
	ifstream img_filename(img_filename_list);
	string img_filename_line;
	Mat img;
	namedWindow("People Detector", 1);
	while(getline(img_filename, img_filename_line)) {

		img = HOGSVMDetectShow(img_filename_line);

		imshow("People Detector", img);

		int c = waitKey(0) & 255;
		if( c == 'q' || c == 'Q')
			break;
	}
}
void Detectors::HOGSVMDetectBuclePrint(string img_filename_list, string folder, Sigmoid sig)
{
	ifstream img_filename(img_filename_list);
	string img_filename_line;
	while(getline(img_filename, img_filename_line)) {
		NeighbourhoodMatrix neighbourhood_matrix(HOGSVMDetectPrint(img_filename_line, sig));
		img_filename_line.erase(img_filename_line.find_last_of("."), string::npos);
		img_filename_line.erase(0,img_filename_line.find_last_of("/")+1);
		string file = folder+img_filename_line+boost::lexical_cast<string>(".mat");
		neighbourhood_matrix.WriteNeigbourhoodMatrix(file);
		cout << file << endl;
	}

}
//Deteccion con HOG + Adaboost unitaria
Mat Detectors::HOGAdaboostDetectShow(string filename)
{
	Mat img;
	img = imread(filename);
	if(!img.data)
		return img;
	vector<float> descriptor_result;
	for (int x = 3; x < (img.cols-3-hog.winSize.width); x++)
	{
		for (int y = 3; y < (img.rows-3-hog.winSize.height); y++)
		{
			Rect roi(x,y,hog.winSize.width,hog.winSize.height);
			Mat crop = img(roi);
			hog.compute(crop,descriptor_result);
			Mat crop_hog = Mat(1,descriptor_result.size(),CV_32FC1);
			for (int i = 0; i < descriptor_result.size(); i++)
			{
				crop_hog.at<float>(0,i) = descriptor_result[i];
			}

			float result = boost.predict(crop_hog,Mat(),Range::all(),false,true);

			Point ce = Point((roi.tl().x+roi.br().x)/2,(roi.tl().y+roi.br().y)/2);
			line( img, ce,ce, Scalar(0, 0, 255*result),1,8);
			//rectangle(img, roi.tl(), roi.br(), cv::Scalar(0,255*result,0), 1);
		}
	}
	return img;
}
//Deteccion con HOG + SVM unitaria
Mat Detectors::HOGAdaboostDetectShow(string filename, string boost_model)
{
	this->boost.load(boost_model.c_str());
	return HOGAdaboostDetectShow(filename);
}
//
NeighbourhoodMatrix Detectors::HOGAdaboostDetectPrint(string filename, Sigmoid sig)
{
	Mat img;
	img = imread(filename);
	NeighbourhoodMatrix null_matrix;
	if(!img.data)
		return null_matrix;
	int rows = img.rows-6-hog.winSize.height;
	int cols = img.cols-6-hog.winSize.width;
	vector<vector<double>> matrix =  vector<vector<double>>(rows, vector<double>(cols,0.0));
	#pragma omp parallel num_threads(34)
	{
		vector<float> descriptor_result;
		#pragma omp for schedule(dynamic,rows/50)
		for (int x = 3; x < (img.cols-3-hog.winSize.width); x++)
		{

			for (int y = 3; y < (img.rows-3-hog.winSize.height); y++)
			{
				Rect roi(x,y,hog.winSize.width,hog.winSize.height);
				Mat crop = img(roi);
				hog.compute(crop,descriptor_result);
				Mat crop_hog = Mat(1,descriptor_result.size(),CV_32FC1);
				for (int i = 0; i < descriptor_result.size(); i++)
				{
					crop_hog.at<float>(0,i) = descriptor_result[i];
				}
				float result = sig.EvaluateSigmoid(boost.predict(crop_hog,Mat(),Range::all(),false,true));
				#pragma omp critical
				matrix[y-3][x-3] = (double)result;
			}
		}
	}
	NeighbourhoodMatrix neighbourhood_matrix(matrix);

	return neighbourhood_matrix;
}
NeighbourhoodMatrix Detectors::HOGAdaboostDetectPrint(string filename, string boost_model, Sigmoid sig)
{
	this->boost.load(boost_model.c_str());
	return HOGAdaboostDetectPrint(filename, sig);
}
//Deteccion con SVM bucle
void Detectors::HOGAdaboostDetectBucleShow(string img_filename_list)
{
	ifstream img_filename(img_filename_list);
	string img_filename_line;
	Mat img;
	namedWindow("People Detector", 1);
	while(getline(img_filename, img_filename_line)) {

		img = HOGAdaboostDetectShow(img_filename_line);

		imshow("People Detector", img);

		int c = waitKey(0) & 255;
		if( c == 'q' || c == 'Q')
			break;
	}
}
void Detectors::HOGAdaboostDetectBuclePrint(string img_filename_list,string folder, Sigmoid sig)
{
	ifstream img_filename(img_filename_list);
	string img_filename_line;
	while(getline(img_filename, img_filename_line)) {
		NeighbourhoodMatrix neighbourhood_matrix(HOGAdaboostDetectPrint(img_filename_line, sig));
		img_filename_line.erase(img_filename_line.find_last_of("."), string::npos);
		img_filename_line.erase(0,img_filename_line.find_last_of("/")+1);
		string file = folder+img_filename_line+boost::lexical_cast<string>(".mat");
		neighbourhood_matrix.WriteNeigbourhoodMatrix(file);
		cout << file << endl;
	}

}
<|endoftext|>


<commit_before>#ifndef CINSERT_ITERATOR
#define CINSERT_ITERATOR
#include<iterator>
#include<memory>	//addressof
#include<utility>	//declval, move

namespace nTool
{
	template<class T,class Holder,class RefFunc_t,RefFunc_t RefFunc,class MoveFunc_t=RefFunc_t,MoveFunc_t MoveFunc=RefFunc>
	class CInsert_iterator:public std::iterator<std::output_iterator_tag,void,void,void,void>
	{
		Holder *hold_;
	public:
		using holder_type=Holder;
		using value_type=T;
		explicit CInsert_iterator(Holder &hold) noexcept
			:hold_{std::addressof(hold)}{}
		inline CInsert_iterator& operator*() noexcept
		{
			return *this;
		}
		inline CInsert_iterator& operator++() noexcept
		{
			return *this;
		}
		inline CInsert_iterator& operator++(const int) noexcept
		{
			return *this;
		}
		CInsert_iterator& operator=(const value_type &val) noexcept(noexcept((std::declval<Holder>().*RefFunc)(std::declval<value_type&>())))
		{
			(hold_->*RefFunc)(val);
			return *this;
		}
		CInsert_iterator& operator=(value_type &&val) noexcept(noexcept((std::declval<Holder>().*MoveFunc)(std::declval<value_type>())))
		{
			(hold_->*MoveFunc)(std::move(val));
			return *this;
		}
	};

	template<class T,class RefFunc_t,RefFunc_t RefFunc,class MoveFunc_t,MoveFunc_t MoveFunc,class Holder>
	inline CInsert_iterator<T,Holder,RefFunc_t,RefFunc,MoveFunc_t,MoveFunc> inserter(Holder &holder)
	{
		return CInsert_iterator<T,Holder,RefFunc_t,RefFunc,MoveFunc_t,MoveFunc>{holder};
	}

	template<class T,class RefFunc_t,RefFunc_t RefFunc,class Holder>
	inline CInsert_iterator<T,Holder,RefFunc_t,RefFunc> inserter(Holder &holder)
	{
		return CInsert_iterator<T,Holder,RefFunc_t,RefFunc>{holder};
	}
}

#endif<commit_msg>fix type name<commit_after>#ifndef CINSERT_ITERATOR
#define CINSERT_ITERATOR
#include<iterator>
#include<memory>	//addressof
#include<utility>	//declval, move

namespace nTool
{
	template<class T,class Holder,class RefFunc_t,RefFunc_t RefFunc,class MoveFunc_t=RefFunc_t,MoveFunc_t MoveFunc=RefFunc>
	class CInsert_iterator:public std::iterator<std::output_iterator_tag,void,void,void,void>
	{
		Holder *hold_;
	public:
		using holder_type=Holder;
		using value_type=T;
		explicit CInsert_iterator(holder_type &hold) noexcept
			:hold_{std::addressof(hold)}{}
		inline CInsert_iterator& operator*() noexcept
		{
			return *this;
		}
		inline CInsert_iterator& operator++() noexcept
		{
			return *this;
		}
		inline CInsert_iterator& operator++(const int) noexcept
		{
			return *this;
		}
		CInsert_iterator& operator=(const value_type &val) noexcept(noexcept((std::declval<holder_type>().*RefFunc)(std::declval<value_type&>())))
		{
			(hold_->*RefFunc)(val);
			return *this;
		}
		CInsert_iterator& operator=(value_type &&val) noexcept(noexcept((std::declval<holder_type>().*MoveFunc)(std::declval<value_type>())))
		{
			(hold_->*MoveFunc)(std::move(val));
			return *this;
		}
	};

	template<class T,class RefFunc_t,RefFunc_t RefFunc,class MoveFunc_t,MoveFunc_t MoveFunc,class Holder>
	inline CInsert_iterator<T,Holder,RefFunc_t,RefFunc,MoveFunc_t,MoveFunc> inserter(Holder &holder)
	{
		return CInsert_iterator<T,Holder,RefFunc_t,RefFunc,MoveFunc_t,MoveFunc>{holder};
	}

	template<class T,class RefFunc_t,RefFunc_t RefFunc,class Holder>
	inline CInsert_iterator<T,Holder,RefFunc_t,RefFunc> inserter(Holder &holder)
	{
		return CInsert_iterator<T,Holder,RefFunc_t,RefFunc>{holder};
	}
}

#endif<|endoftext|>


<commit_before>#include "../utils/utils.hpp"
#include <stdint.h>
#include <ctime>

Rand randgen(time(NULL));

// From Numerical Recipes

static const uint64_t Mul = 2685821657736338717LL;
static const uint64_t Vini = 4101842887655102017LL;
static const double Fl = 5.42101086242752217e-20;

Rand::Rand(unsigned long seed) : theseed(seed) {
	v = Vini ^ seed;
	v = bits();
}

unsigned long Rand::bits(void)
{
	v ^= v >> 21;
	v ^= v << 35;
	v ^= v >> 4;
	v *= Mul;
	return v;
}

long Rand::integer(long min, long max)
{
	if (min == max)
		return min;

	return bits() % ((max+1) - min) + min;
}

double Rand::real(void) {
	return bits() * Fl;
}<commit_msg>utils: initialize randgen's seed with a finer-grained time.<commit_after>#include "../utils/utils.hpp"
#include <stdint.h>
#include <ctime>

Rand randgen(walltime() * 1e9);

// From Numerical Recipes

static const uint64_t Mul = 2685821657736338717LL;
static const uint64_t Vini = 4101842887655102017LL;
static const double Fl = 5.42101086242752217e-20;

Rand::Rand(unsigned long seed) : theseed(seed) {
	v = Vini ^ seed;
	v = bits();
}

unsigned long Rand::bits(void)
{
	v ^= v >> 21;
	v ^= v << 35;
	v ^= v >> 4;
	v *= Mul;
	return v;
}

long Rand::integer(long min, long max)
{
	if (min == max)
		return min;

	return bits() % ((max+1) - min) + min;
}

double Rand::real(void) {
	return bits() * Fl;
}<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "tarpackagecreationstep.h"

#include "remotelinuxdeployconfiguration.h"

#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>

#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QFileInfo>

#include <cstring>

using namespace ProjectExplorer;

namespace RemoteLinux {
namespace {

class CreateTarStepWidget : public SimpleBuildStepConfigWidget
{
    Q_OBJECT
public:
    CreateTarStepWidget(TarPackageCreationStep *step) : SimpleBuildStepConfigWidget(step)
    {
        connect(step, SIGNAL(packageFilePathChanged()), SIGNAL(updateSummary()));
    }

    QString summaryText() const
    {
        TarPackageCreationStep * const step = qobject_cast<TarPackageCreationStep *>(this->step());
        if (step->packageFilePath().isEmpty()) {
            return QLatin1String("")
                + tr("Tarball creation not possible.") + QLatin1String("");
        }
        return QLatin1String("") + tr("Create tarball:") + QLatin1String(" ")
            + step->packageFilePath();
    }
};

const int TarBlockSize = 512;
struct TarFileHeader {
    char fileName[100];
    char fileMode[8];
    char uid[8];
    char gid[8];
    char length[12];
    char mtime[12];
    char chksum[8];
    char typeflag;
    char linkname[100];
    char magic[6];
    char version[2];
    char uname[32];
    char gname[32];
    char devmajor[8];
    char devminor[8];
    char fileNamePrefix[155];
    char padding[12];
};

} // Anonymous namespace.

TarPackageCreationStep::TarPackageCreationStep(BuildStepList *bsl)
    : AbstractPackagingStep(bsl, stepId())
{
    ctor();
}

TarPackageCreationStep::TarPackageCreationStep(BuildStepList *bsl, TarPackageCreationStep *other)
    : AbstractPackagingStep(bsl, other)
{
    ctor();
}

void TarPackageCreationStep::ctor()
{
    setDefaultDisplayName(displayName());
}

bool TarPackageCreationStep::init()
{
    if (!AbstractPackagingStep::init())
        return false;
    m_packagingNeeded = isPackagingNeeded();
    if (m_packagingNeeded)
        m_files = target()->deploymentData().allFiles();
    return true;
}

void TarPackageCreationStep::run(QFutureInterface<bool> &fi)
{
    setPackagingStarted();
    const bool success = doPackage(fi);
    setPackagingFinished(success);
    if (success)
        emit addOutput(tr("Packaging finished successfully."), MessageOutput);
    else
        emit addOutput(tr("Packaging failed."), ErrorMessageOutput);
    fi.reportResult(success);
}

bool TarPackageCreationStep::doPackage(QFutureInterface<bool> &fi)
{
    emit addOutput(tr("Creating tarball..."), MessageOutput);
    if (!m_packagingNeeded) {
        emit addOutput(tr("Tarball up to date, skipping packaging."), MessageOutput);
        return true;
    }

    // TODO: Optimization: Only package changed files
    QFile tarFile(cachedPackageFilePath());

    if (!tarFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        raiseError(tr("Error: tar file %1 cannot be opened (%2).")
            .arg(QDir::toNativeSeparators(cachedPackageFilePath()), tarFile.errorString()));
        return false;
    }

    foreach (const DeployableFile &d, m_files) {
        if (d.remoteDirectory().isEmpty()) {
            emit addOutput(tr("No remote path specified for file '%1', skipping.")
                .arg(d.localFilePath().toUserOutput()), ErrorMessageOutput);
            continue;
        }
        QFileInfo fileInfo = d.localFilePath().toFileInfo();
        if (!appendFile(tarFile, fileInfo, d.remoteDirectory() + QLatin1Char('/')
                + fileInfo.fileName(), fi)) {
            return false;
        }
    }

    const QByteArray eofIndicator(2*sizeof(TarFileHeader), 0);
    if (tarFile.write(eofIndicator) != eofIndicator.length()) {
        raiseError(tr("Error writing tar file '%1': %2.")
            .arg(QDir::toNativeSeparators(tarFile.fileName()), tarFile.errorString()));
        return false;
    }

    return true;
}

bool TarPackageCreationStep::appendFile(QFile &tarFile, const QFileInfo &fileInfo,
    const QString &remoteFilePath, const QFutureInterface<bool> &fi)
{
    if (!writeHeader(tarFile, fileInfo, remoteFilePath))
        return false;
    if (fileInfo.isDir()) {
        QDir dir(fileInfo.absoluteFilePath());
        foreach (const QString &fileName,
                 dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
            const QString thisLocalFilePath = dir.path() + QLatin1Char('/') + fileName;
            const QString thisRemoteFilePath  = remoteFilePath + QLatin1Char('/') + fileName;
            if (!appendFile(tarFile, QFileInfo(thisLocalFilePath), thisRemoteFilePath, fi))
                return false;
        }
        return true;
    }

    const QString nativePath = QDir::toNativeSeparators(fileInfo.filePath());
    QFile file(fileInfo.filePath());
    if (!file.open(QIODevice::ReadOnly)) {
        raiseError(tr("Error reading file '%1': %2.").arg(nativePath, file.errorString()));
        return false;
    }

    const int chunkSize = 1024*1024;

    emit addOutput(tr("Adding file '%1' to tarball...").arg(nativePath), MessageOutput);

    // TODO: Wasteful. Work with fixed-size buffer.
    while (!file.atEnd() && !file.error() != QFile::NoError && !tarFile.error() != QFile::NoError) {
        const QByteArray data = file.read(chunkSize);
        tarFile.write(data);
        if (fi.isCanceled())
            return false;
    }
    if (file.error() != QFile::NoError) {
        raiseError(tr("Error reading file '%1': %2.").arg(nativePath, file.errorString()));
        return false;
    }

    const int blockModulo = file.size() % TarBlockSize;
    if (blockModulo != 0)
        tarFile.write(QByteArray(TarBlockSize - blockModulo, 0));

    if (tarFile.error() != QFile::NoError) {
        raiseError(tr("Error writing tar file '%1': %2.")
            .arg(QDir::toNativeSeparators(tarFile.fileName()), tarFile.errorString()));
        return false;
    }
    return true;
}

bool TarPackageCreationStep::writeHeader(QFile &tarFile, const QFileInfo &fileInfo,
    const QString &remoteFilePath)
{
    TarFileHeader header;
    std::memset(&header, '\0', sizeof header);
    const QByteArray &filePath = remoteFilePath.toUtf8();
    const int maxFilePathLength = sizeof header.fileNamePrefix + sizeof header.fileName;
    if (filePath.count() > maxFilePathLength) {
        raiseError(tr("Cannot add file '%1' to tar-archive: path too long.")
            .arg(QDir::toNativeSeparators(remoteFilePath)));
        return false;
    }

    const int fileNameBytesToWrite = qMin<int>(filePath.length(), sizeof header.fileName);
    const int fileNameOffset = filePath.length() - fileNameBytesToWrite;
    std::memcpy(&header.fileName, filePath.data() + fileNameOffset, fileNameBytesToWrite);
    if (fileNameOffset > 0)
        std::memcpy(&header.fileNamePrefix, filePath.data(), fileNameOffset);
    int permissions = (0400 * fileInfo.permission(QFile::ReadOwner))
        | (0200 * fileInfo.permission(QFile::WriteOwner))
        | (0100 * fileInfo.permission(QFile::ExeOwner))
        | (040 * fileInfo.permission(QFile::ReadGroup))
        | (020 * fileInfo.permission(QFile::WriteGroup))
        | (010 * fileInfo.permission(QFile::ExeGroup))
        | (04 * fileInfo.permission(QFile::ReadOther))
        | (02 * fileInfo.permission(QFile::WriteOther))
        | (01 * fileInfo.permission(QFile::ExeOther));
    const QByteArray permissionString = QString::fromLatin1("%1").arg(permissions,
        sizeof header.fileMode - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.fileMode, permissionString.data(), permissionString.length());
    const QByteArray uidString = QString::fromLatin1("%1").arg(fileInfo.ownerId(),
        sizeof header.uid - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.uid, uidString.data(), uidString.length());
    const QByteArray gidString = QString::fromLatin1("%1").arg(fileInfo.groupId(),
        sizeof header.gid - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.gid, gidString.data(), gidString.length());
    const QByteArray sizeString = QString::fromLatin1("%1").arg(fileInfo.size(),
        sizeof header.length - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.length, sizeString.data(), sizeString.length());
    const QByteArray mtimeString = QString::fromLatin1("%1").arg(fileInfo.lastModified().toTime_t(),
        sizeof header.mtime - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.mtime, mtimeString.data(), mtimeString.length());
    if (fileInfo.isDir())
        header.typeflag = '5';
    std::memcpy(&header.magic, "ustar", sizeof "ustar");
    std::memcpy(&header.version, "00", 2);
    const QByteArray &owner = fileInfo.owner().toUtf8();
    std::memcpy(&header.uname, owner.data(), qMin<int>(owner.length(), sizeof header.uname - 1));
    const QByteArray &group = fileInfo.group().toUtf8();
    std::memcpy(&header.gname, group.data(), qMin<int>(group.length(), sizeof header.gname - 1));
    std::memset(&header.chksum, ' ', sizeof header.chksum);
    quint64 checksum = 0;
    for (size_t i = 0; i < sizeof header; ++i)
        checksum += reinterpret_cast<char *>(&header)[i];
    const QByteArray checksumString = QString::fromLatin1("%1").arg(checksum,
        sizeof header.chksum - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.chksum, checksumString.data(), checksumString.length());
    header.chksum[sizeof header.chksum-1] = 0;
    if (!tarFile.write(reinterpret_cast<char *>(&header), sizeof header)) {
        raiseError(tr("Error writing tar file '%1': %2")
           .arg(QDir::toNativeSeparators(cachedPackageFilePath()), tarFile.errorString()));
        return false;
    }
    return true;
}

QString TarPackageCreationStep::packageFileName() const
{
    return project()->displayName() + QLatin1String(".tar");
}

BuildStepConfigWidget *TarPackageCreationStep::createConfigWidget()
{
    return new CreateTarStepWidget(this);
}

Core::Id TarPackageCreationStep::stepId()
{
    return Core::Id("MaemoTarPackageCreationStep");
}

QString TarPackageCreationStep::displayName()
{
    return tr("Create tarball");
}

} // namespace RemoteLinux

#include "tarpackagecreationstep.moc"
<commit_msg>TarPackageCreationStep: Use static_cast not qobject_cast<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "tarpackagecreationstep.h"

#include "remotelinuxdeployconfiguration.h"

#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>

#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QFileInfo>

#include <cstring>

using namespace ProjectExplorer;

namespace RemoteLinux {
namespace {

class CreateTarStepWidget : public SimpleBuildStepConfigWidget
{
    Q_OBJECT
public:
    CreateTarStepWidget(TarPackageCreationStep *step) : SimpleBuildStepConfigWidget(step)
    {
        connect(step, SIGNAL(packageFilePathChanged()), SIGNAL(updateSummary()));
    }

    QString summaryText() const
    {
        TarPackageCreationStep * const step = static_cast<TarPackageCreationStep *>(this->step());
        if (step->packageFilePath().isEmpty()) {
            return QLatin1String("")
                + tr("Tarball creation not possible.") + QLatin1String("");
        }
        return QLatin1String("") + tr("Create tarball:") + QLatin1String(" ")
            + step->packageFilePath();
    }
};

const int TarBlockSize = 512;
struct TarFileHeader {
    char fileName[100];
    char fileMode[8];
    char uid[8];
    char gid[8];
    char length[12];
    char mtime[12];
    char chksum[8];
    char typeflag;
    char linkname[100];
    char magic[6];
    char version[2];
    char uname[32];
    char gname[32];
    char devmajor[8];
    char devminor[8];
    char fileNamePrefix[155];
    char padding[12];
};

} // Anonymous namespace.

TarPackageCreationStep::TarPackageCreationStep(BuildStepList *bsl)
    : AbstractPackagingStep(bsl, stepId())
{
    ctor();
}

TarPackageCreationStep::TarPackageCreationStep(BuildStepList *bsl, TarPackageCreationStep *other)
    : AbstractPackagingStep(bsl, other)
{
    ctor();
}

void TarPackageCreationStep::ctor()
{
    setDefaultDisplayName(displayName());
}

bool TarPackageCreationStep::init()
{
    if (!AbstractPackagingStep::init())
        return false;
    m_packagingNeeded = isPackagingNeeded();
    if (m_packagingNeeded)
        m_files = target()->deploymentData().allFiles();
    return true;
}

void TarPackageCreationStep::run(QFutureInterface<bool> &fi)
{
    setPackagingStarted();
    const bool success = doPackage(fi);
    setPackagingFinished(success);
    if (success)
        emit addOutput(tr("Packaging finished successfully."), MessageOutput);
    else
        emit addOutput(tr("Packaging failed."), ErrorMessageOutput);
    fi.reportResult(success);
}

bool TarPackageCreationStep::doPackage(QFutureInterface<bool> &fi)
{
    emit addOutput(tr("Creating tarball..."), MessageOutput);
    if (!m_packagingNeeded) {
        emit addOutput(tr("Tarball up to date, skipping packaging."), MessageOutput);
        return true;
    }

    // TODO: Optimization: Only package changed files
    QFile tarFile(cachedPackageFilePath());

    if (!tarFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        raiseError(tr("Error: tar file %1 cannot be opened (%2).")
            .arg(QDir::toNativeSeparators(cachedPackageFilePath()), tarFile.errorString()));
        return false;
    }

    foreach (const DeployableFile &d, m_files) {
        if (d.remoteDirectory().isEmpty()) {
            emit addOutput(tr("No remote path specified for file '%1', skipping.")
                .arg(d.localFilePath().toUserOutput()), ErrorMessageOutput);
            continue;
        }
        QFileInfo fileInfo = d.localFilePath().toFileInfo();
        if (!appendFile(tarFile, fileInfo, d.remoteDirectory() + QLatin1Char('/')
                + fileInfo.fileName(), fi)) {
            return false;
        }
    }

    const QByteArray eofIndicator(2*sizeof(TarFileHeader), 0);
    if (tarFile.write(eofIndicator) != eofIndicator.length()) {
        raiseError(tr("Error writing tar file '%1': %2.")
            .arg(QDir::toNativeSeparators(tarFile.fileName()), tarFile.errorString()));
        return false;
    }

    return true;
}

bool TarPackageCreationStep::appendFile(QFile &tarFile, const QFileInfo &fileInfo,
    const QString &remoteFilePath, const QFutureInterface<bool> &fi)
{
    if (!writeHeader(tarFile, fileInfo, remoteFilePath))
        return false;
    if (fileInfo.isDir()) {
        QDir dir(fileInfo.absoluteFilePath());
        foreach (const QString &fileName,
                 dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
            const QString thisLocalFilePath = dir.path() + QLatin1Char('/') + fileName;
            const QString thisRemoteFilePath  = remoteFilePath + QLatin1Char('/') + fileName;
            if (!appendFile(tarFile, QFileInfo(thisLocalFilePath), thisRemoteFilePath, fi))
                return false;
        }
        return true;
    }

    const QString nativePath = QDir::toNativeSeparators(fileInfo.filePath());
    QFile file(fileInfo.filePath());
    if (!file.open(QIODevice::ReadOnly)) {
        raiseError(tr("Error reading file '%1': %2.").arg(nativePath, file.errorString()));
        return false;
    }

    const int chunkSize = 1024*1024;

    emit addOutput(tr("Adding file '%1' to tarball...").arg(nativePath), MessageOutput);

    // TODO: Wasteful. Work with fixed-size buffer.
    while (!file.atEnd() && !file.error() != QFile::NoError && !tarFile.error() != QFile::NoError) {
        const QByteArray data = file.read(chunkSize);
        tarFile.write(data);
        if (fi.isCanceled())
            return false;
    }
    if (file.error() != QFile::NoError) {
        raiseError(tr("Error reading file '%1': %2.").arg(nativePath, file.errorString()));
        return false;
    }

    const int blockModulo = file.size() % TarBlockSize;
    if (blockModulo != 0)
        tarFile.write(QByteArray(TarBlockSize - blockModulo, 0));

    if (tarFile.error() != QFile::NoError) {
        raiseError(tr("Error writing tar file '%1': %2.")
            .arg(QDir::toNativeSeparators(tarFile.fileName()), tarFile.errorString()));
        return false;
    }
    return true;
}

bool TarPackageCreationStep::writeHeader(QFile &tarFile, const QFileInfo &fileInfo,
    const QString &remoteFilePath)
{
    TarFileHeader header;
    std::memset(&header, '\0', sizeof header);
    const QByteArray &filePath = remoteFilePath.toUtf8();
    const int maxFilePathLength = sizeof header.fileNamePrefix + sizeof header.fileName;
    if (filePath.count() > maxFilePathLength) {
        raiseError(tr("Cannot add file '%1' to tar-archive: path too long.")
            .arg(QDir::toNativeSeparators(remoteFilePath)));
        return false;
    }

    const int fileNameBytesToWrite = qMin<int>(filePath.length(), sizeof header.fileName);
    const int fileNameOffset = filePath.length() - fileNameBytesToWrite;
    std::memcpy(&header.fileName, filePath.data() + fileNameOffset, fileNameBytesToWrite);
    if (fileNameOffset > 0)
        std::memcpy(&header.fileNamePrefix, filePath.data(), fileNameOffset);
    int permissions = (0400 * fileInfo.permission(QFile::ReadOwner))
        | (0200 * fileInfo.permission(QFile::WriteOwner))
        | (0100 * fileInfo.permission(QFile::ExeOwner))
        | (040 * fileInfo.permission(QFile::ReadGroup))
        | (020 * fileInfo.permission(QFile::WriteGroup))
        | (010 * fileInfo.permission(QFile::ExeGroup))
        | (04 * fileInfo.permission(QFile::ReadOther))
        | (02 * fileInfo.permission(QFile::WriteOther))
        | (01 * fileInfo.permission(QFile::ExeOther));
    const QByteArray permissionString = QString::fromLatin1("%1").arg(permissions,
        sizeof header.fileMode - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.fileMode, permissionString.data(), permissionString.length());
    const QByteArray uidString = QString::fromLatin1("%1").arg(fileInfo.ownerId(),
        sizeof header.uid - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.uid, uidString.data(), uidString.length());
    const QByteArray gidString = QString::fromLatin1("%1").arg(fileInfo.groupId(),
        sizeof header.gid - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.gid, gidString.data(), gidString.length());
    const QByteArray sizeString = QString::fromLatin1("%1").arg(fileInfo.size(),
        sizeof header.length - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.length, sizeString.data(), sizeString.length());
    const QByteArray mtimeString = QString::fromLatin1("%1").arg(fileInfo.lastModified().toTime_t(),
        sizeof header.mtime - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.mtime, mtimeString.data(), mtimeString.length());
    if (fileInfo.isDir())
        header.typeflag = '5';
    std::memcpy(&header.magic, "ustar", sizeof "ustar");
    std::memcpy(&header.version, "00", 2);
    const QByteArray &owner = fileInfo.owner().toUtf8();
    std::memcpy(&header.uname, owner.data(), qMin<int>(owner.length(), sizeof header.uname - 1));
    const QByteArray &group = fileInfo.group().toUtf8();
    std::memcpy(&header.gname, group.data(), qMin<int>(group.length(), sizeof header.gname - 1));
    std::memset(&header.chksum, ' ', sizeof header.chksum);
    quint64 checksum = 0;
    for (size_t i = 0; i < sizeof header; ++i)
        checksum += reinterpret_cast<char *>(&header)[i];
    const QByteArray checksumString = QString::fromLatin1("%1").arg(checksum,
        sizeof header.chksum - 1, 8, QLatin1Char('0')).toLatin1();
    std::memcpy(&header.chksum, checksumString.data(), checksumString.length());
    header.chksum[sizeof header.chksum-1] = 0;
    if (!tarFile.write(reinterpret_cast<char *>(&header), sizeof header)) {
        raiseError(tr("Error writing tar file '%1': %2")
           .arg(QDir::toNativeSeparators(cachedPackageFilePath()), tarFile.errorString()));
        return false;
    }
    return true;
}

QString TarPackageCreationStep::packageFileName() const
{
    return project()->displayName() + QLatin1String(".tar");
}

BuildStepConfigWidget *TarPackageCreationStep::createConfigWidget()
{
    return new CreateTarStepWidget(this);
}

Core::Id TarPackageCreationStep::stepId()
{
    return Core::Id("MaemoTarPackageCreationStep");
}

QString TarPackageCreationStep::displayName()
{
    return tr("Create tarball");
}

} // namespace RemoteLinux

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


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "communitywelcomepagewidget.h"
#include "ui_communitywelcomepagewidget.h"

#include "rssfetcher.h"

#include <QtCore/QMap>
#include <QtCore/QUrl>
#include <QtGui/QDesktopServices>
#include <QtGui/QTreeWidgetItem>

struct Site {
    const char *description;
    const char *url;
};

static const Site supportSites[] = {
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Forum Nokia
Mobile Application Support"),
      "http://www.forum.nokia.com/I_Want_To/Develop_Mobile_Applications/Technical_Support/"},
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Qt LGPL Support
Buy commercial Qt support"),
      "http://shop.qt.nokia.com/en/support.html"},
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Qt Centre
Community based Qt support"),
      "http://www.qtcentre.org" }
};

static const Site sites[] = {
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Qt Home
Qt by Nokia on the web"),
      "http://qt.nokia.com" },
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Qt Git Hosting
Participate in Qt development"),
      "http://qt.gitorious.org"},
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Qt Apps
Find free Qt-based apps"),
      "http://www.qt-apps.org"}
};

namespace Welcome {
namespace Internal {

static inline void populateWelcomeTreeWidget(const Site *sites, int count, Utils::WelcomeModeTreeWidget *wt)
{
    for (int s = 0; s < count; s++) {
        const QString description = CommunityWelcomePageWidget::tr(sites[s].description);
        const QString url = QLatin1String(sites[s].url);
        wt->addItem(description, url, url);
    }
}

CommunityWelcomePageWidget::CommunityWelcomePageWidget(QWidget *parent) :
    QWidget(parent),
    m_rssFetcher(new RSSFetcher(7)),
    ui(new Ui::CommunityWelcomePageWidget)
{
    ui->setupUi(this);

    connect(ui->newsTreeWidget, SIGNAL(activated(QString)), SLOT(slotUrlClicked(QString)));
    connect(ui->miscSitesTreeWidget, SIGNAL(activated(QString)), SLOT(slotUrlClicked(QString)));
    connect(ui->supportSitesTreeWidget, SIGNAL(activated(QString)), SLOT(slotUrlClicked(QString)));

    connect(m_rssFetcher, SIGNAL(newsItemReady(QString, QString, QString)),
            ui->newsTreeWidget, SLOT(addNewsItem(QString, QString, QString)), Qt::QueuedConnection);
    connect(this, SIGNAL(startRssFetching(QUrl)), m_rssFetcher, SLOT(fetch(QUrl)), Qt::QueuedConnection);

    //: Add localized feed here only if one exists
    m_rssFetcher->start(QThread::LowestPriority);
    emit startRssFetching(QUrl(tr("http://labs.trolltech.com/blogs/feed")));

    populateWelcomeTreeWidget(supportSites, sizeof(supportSites)/sizeof(Site), ui->supportSitesTreeWidget);
    populateWelcomeTreeWidget(sites, sizeof(sites)/sizeof(Site), ui->miscSitesTreeWidget);
}

CommunityWelcomePageWidget::~CommunityWelcomePageWidget()
{
    m_rssFetcher->exit();
    m_rssFetcher->wait();
    delete m_rssFetcher;
    delete ui;
}

void CommunityWelcomePageWidget::slotUrlClicked(const QString &data)
{
    QDesktopServices::openUrl(QUrl(data));
}

} // namespace Internal
} // namespace Welcome
<commit_msg>Add Qt DevNet to link page, dropped QtCentre instead.<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "communitywelcomepagewidget.h"
#include "ui_communitywelcomepagewidget.h"

#include "rssfetcher.h"

#include <QtCore/QMap>
#include <QtCore/QUrl>
#include <QtGui/QDesktopServices>
#include <QtGui/QTreeWidgetItem>

struct Site {
    const char *description;
    const char *url;
};

static const Site supportSites[] = {
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Forum Nokia
Mobile application support"),
      "http://www.forum.nokia.com/I_Want_To/Develop_Mobile_Applications/Technical_Support/"},
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Qt LGPL Support
Buy commercial Qt support"),
      "http://shop.qt.nokia.com/en/support.html"},
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Qt DevNet
Qt Developer Resources"),
      "http://developer.qt.nokia.com" }
};

static const Site sites[] = {
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Qt Home
Qt by Nokia on the web"),
      "http://qt.nokia.com" },
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Qt Git Hosting
Participate in Qt development"),
      "http://qt.gitorious.org"},
    { QT_TRANSLATE_NOOP("Welcome::Internal::CommunityWelcomePageWidget",
                        "Qt Apps
Find free Qt-based apps"),
      "http://www.qt-apps.org"}
};

namespace Welcome {
namespace Internal {

static inline void populateWelcomeTreeWidget(const Site *sites, int count, Utils::WelcomeModeTreeWidget *wt)
{
    for (int s = 0; s < count; s++) {
        const QString description = CommunityWelcomePageWidget::tr(sites[s].description);
        const QString url = QLatin1String(sites[s].url);
        wt->addItem(description, url, url);
    }
}

CommunityWelcomePageWidget::CommunityWelcomePageWidget(QWidget *parent) :
    QWidget(parent),
    m_rssFetcher(new RSSFetcher(7)),
    ui(new Ui::CommunityWelcomePageWidget)
{
    ui->setupUi(this);

    connect(ui->newsTreeWidget, SIGNAL(activated(QString)), SLOT(slotUrlClicked(QString)));
    connect(ui->miscSitesTreeWidget, SIGNAL(activated(QString)), SLOT(slotUrlClicked(QString)));
    connect(ui->supportSitesTreeWidget, SIGNAL(activated(QString)), SLOT(slotUrlClicked(QString)));

    connect(m_rssFetcher, SIGNAL(newsItemReady(QString, QString, QString)),
            ui->newsTreeWidget, SLOT(addNewsItem(QString, QString, QString)), Qt::QueuedConnection);
    connect(this, SIGNAL(startRssFetching(QUrl)), m_rssFetcher, SLOT(fetch(QUrl)), Qt::QueuedConnection);

    //: Add localized feed here only if one exists
    m_rssFetcher->start(QThread::LowestPriority);
    emit startRssFetching(QUrl(tr("http://labs.trolltech.com/blogs/feed")));

    populateWelcomeTreeWidget(supportSites, sizeof(supportSites)/sizeof(Site), ui->supportSitesTreeWidget);
    populateWelcomeTreeWidget(sites, sizeof(sites)/sizeof(Site), ui->miscSitesTreeWidget);
}

CommunityWelcomePageWidget::~CommunityWelcomePageWidget()
{
    m_rssFetcher->exit();
    m_rssFetcher->wait();
    delete m_rssFetcher;
    delete ui;
}

void CommunityWelcomePageWidget::slotUrlClicked(const QString &data)
{
    QDesktopServices::openUrl(QUrl(data));
}

} // namespace Internal
} // namespace Welcome
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, Shogun Toolbox Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:

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

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

#include <shogun/neuralnets/NeuralConvolutionalLayer.h>
#include <shogun/mathematics/Math.h>
#include <shogun/lib/SGVector.h>

using namespace shogun;

CNeuralConvolutionalLayer::CNeuralConvolutionalLayer() : CNeuralLayer()
{
	init();
}

CNeuralConvolutionalLayer::CNeuralConvolutionalLayer(
		EConvMapActivationFunction function,
		int32_t num_maps,
		int32_t radius_x, int32_t radius_y,
		int32_t pooling_width, int32_t pooling_height,
		int32_t stride_x, int32_t stride_y) : CNeuralLayer()
{
	init();
	m_num_maps = num_maps;
	m_radius_x = radius_x;
	m_radius_y = radius_y;
	m_pooling_width = pooling_width;
	m_pooling_height = pooling_height;
	m_stride_x = stride_x;
	m_stride_y = stride_y;
}

void CNeuralConvolutionalLayer::set_batch_size(int32_t batch_size)
{
	CNeuralLayer::set_batch_size(batch_size);

	if (autoencoder_position==NLAP_NONE)
		m_convolution_output = SGMatrix<float64_t>(m_num_maps*
			(m_input_width/m_stride_x)*(m_input_height/m_stride_y), batch_size);
	else
		m_convolution_output = SGMatrix<float64_t>(
			m_num_maps*m_input_width*m_input_height, batch_size);

	m_max_indices = SGMatrix<float64_t>(m_num_neurons, m_batch_size);

	m_convolution_output_gradients = SGMatrix<float64_t>(
		m_convolution_output.num_rows, m_convolution_output.num_cols);
}

void CNeuralConvolutionalLayer::initialize(CDynamicObjectArray* layers,
		SGVector< int32_t > input_indices)
{
	CNeuralLayer* first_input_layer =
		(CNeuralLayer*)layers->element(input_indices[0]);

	m_input_width = first_input_layer->get_width();
	m_input_height = first_input_layer->get_height();

	if (autoencoder_position==NLAP_NONE)
	{
		m_width = m_input_width/(m_stride_x*m_pooling_width);
		m_height = m_input_height/(m_stride_y*m_pooling_height);
	}
	else
	{
		m_width = m_input_width;
		m_height = m_input_height;
	}

	m_num_neurons = m_width*m_height*m_num_maps;

	CNeuralLayer::initialize(layers, input_indices);

	m_input_num_channels = 0;
	for (int32_t l=0; l<input_indices.vlen; l++)
	{
		CNeuralLayer* layer =
			(CNeuralLayer*)layers->element(input_indices[l]);

		m_input_num_channels += layer->get_num_neurons()/(m_input_height*m_input_width);

		SG_UNREF(layer);
	}

	// one bias for each map and one weight matrix between each map in this
	// layer and each channel in the input layers
	m_num_parameters =
		m_num_maps*(1 + m_input_num_channels*(2*m_radius_x+1)*(2*m_radius_y+1));
}

void CNeuralConvolutionalLayer::initialize_parameters(SGVector<float64_t> parameters,
		SGVector<bool> parameter_regularizable,
		float64_t sigma)
{
	int32_t num_parameters_per_map =
		1 + m_input_num_channels*(2*m_radius_x+1)*(2*m_radius_y+1);

	for (int32_t m=0; m<m_num_maps; m++)
	{
		float64_t* map_params = parameters.vector+m*num_parameters_per_map;
		bool* map_param_regularizable =
			parameter_regularizable.vector+m*num_parameters_per_map;

		for (int32_t i=0; i<num_parameters_per_map; i++)
		{
			map_params[i] = CMath::normal_random(0.0, sigma);

			// turn off regularization for the bias, on for the rest of the parameters
			map_param_regularizable[i] = (i != 0);
		}
	}
}

void CNeuralConvolutionalLayer::compute_activations(
		SGVector<float64_t> parameters,
		CDynamicObjectArray* layers)
{
	int32_t num_parameters_per_map =
		1 + m_input_num_channels*(2*m_radius_x+1)*(2*m_radius_y+1);

	for (int32_t m=0; m<m_num_maps; m++)
	{
		SGVector<float64_t> map_params(
			parameters.vector+m*num_parameters_per_map,
			num_parameters_per_map, false);

		CConvolutionalFeatureMap map(m_input_width, m_input_height,
			m_radius_x, m_radius_y, m_stride_x, m_stride_y, m,
			m_activation_function, autoencoder_position);

		map.compute_activations(map_params, layers, m_input_indices,
			m_convolution_output);

		map.pool_activations(m_convolution_output,
			m_pooling_width, m_pooling_height, m_activations, m_max_indices);
	}
}

void CNeuralConvolutionalLayer::compute_gradients(
		SGVector<float64_t> parameters,
		SGMatrix<float64_t> targets,
		CDynamicObjectArray* layers,
		SGVector<float64_t> parameter_gradients)
{
	if (targets.num_rows != 0)
	{
		// sqaured error measure
		// local_gradients = activations-targets
		int32_t length = m_num_neurons*m_batch_size;
		for (int32_t i=0; i<length; i++)
			m_activation_gradients[i] = (m_activations[i]-targets[i])/m_batch_size;
	}

	if (dropout_prop>0.0)
	{
		int32_t len = m_num_neurons*m_batch_size;
		for (int32_t i=0; i<len; i++)
			m_activation_gradients[i] *= m_dropout_mask[i];
	}

	// compute the pre-pooling activation gradients
	m_convolution_output_gradients.zero();
	for (int32_t i=0; i<m_num_neurons; i++)
		for (int32_t j=0; j<m_batch_size; j++)
			if (m_max_indices(i,j)!=-1.0)
				m_convolution_output_gradients(m_max_indices(i,j),j) =
					m_activation_gradients(i,j);

	int32_t num_parameters_per_map =
		1 + m_input_num_channels*(2*m_radius_x+1)*(2*m_radius_y+1);

	for (int32_t m=0; m<m_num_maps; m++)
	{
		SGVector<float64_t> map_params(
			parameters.vector+m*num_parameters_per_map,
			num_parameters_per_map, false);

		SGVector<float64_t> map_gradients(
			parameter_gradients.vector+m*num_parameters_per_map,
			num_parameters_per_map, false);

		CConvolutionalFeatureMap map(m_input_width, m_input_height,
			m_radius_x, m_radius_y, m_stride_x, m_stride_y, m,
			m_activation_function, autoencoder_position);

		map.compute_gradients(map_params, m_convolution_output,
			m_convolution_output_gradients, layers,
			m_input_indices, map_gradients);
	}
}

float64_t CNeuralConvolutionalLayer::compute_error(SGMatrix<float64_t> targets)
{
	// error = 0.5*(sum(targets-activations)^2)/batch_size
	float64_t sum = 0;
	int32_t length = m_num_neurons*m_batch_size;
	for (int32_t i=0; i<length; i++)
		sum += (targets[i]-m_activations[i])*(targets[i]-m_activations[i]);
	sum *= (0.5/m_batch_size);
	return sum;
}

void CNeuralConvolutionalLayer::enforce_max_norm(SGVector<float64_t> parameters,
		float64_t max_norm)
{
	int32_t num_weights = (2*m_radius_x+1)*(2*m_radius_y+1);

	int32_t num_parameters_per_map = 1 + m_input_num_channels*num_weights;

	for (int32_t offset=1; offset<parameters.vlen; offset+=num_parameters_per_map)
	{
		float64_t* weights = parameters.vector+offset;

		float64_t norm =
				SGVector<float64_t>::twonorm(weights, num_weights);

		if (norm > max_norm)
		{
			float64_t multiplier = max_norm/norm;
			for (int32_t i=0; i<num_weights; i++)
				weights[i] *= multiplier;
		}
	}
}

void CNeuralConvolutionalLayer::init()
{
	m_num_maps = 1;
	m_input_width = 0;
	m_input_height = 0;
	m_input_num_channels = 0;
	m_radius_x = 0;
	m_radius_y = 0;
	m_pooling_width = 1;
	m_pooling_height = 1;
	m_stride_x = 1;
	m_stride_y = 1;
	m_activation_function = CMAF_IDENTITY;

	SG_ADD(&m_num_maps, "num_maps", "Number of maps", MS_NOT_AVAILABLE);
	SG_ADD(&m_input_width, "input_width", "Input Width", MS_NOT_AVAILABLE);
	SG_ADD(&m_input_height, "input_height", "Input Height", MS_NOT_AVAILABLE);
	SG_ADD(&m_input_num_channels, "input_num_channels", "Input's number of channels",
		MS_NOT_AVAILABLE);
	SG_ADD(&m_radius_x, "radius_x", "X Radius", MS_NOT_AVAILABLE);
	SG_ADD(&m_radius_y, "radius_y", "Y Radius", MS_NOT_AVAILABLE);
	SG_ADD(&m_pooling_width, "pooling_width", "Pooling Width", MS_NOT_AVAILABLE);
	SG_ADD(&m_pooling_height, "pooling_height", "Pooling Height", MS_NOT_AVAILABLE);
	SG_ADD(&m_stride_x, "stride_x", "X Stride", MS_NOT_AVAILABLE);
	SG_ADD(&m_stride_y, "stride_y", "Y Stride", MS_NOT_AVAILABLE);
	SG_ADD((machine_int_t*) &m_activation_function, "activation_function",
		"Activation Function", MS_NOT_AVAILABLE);

	SG_ADD(&m_convolution_output, "convolution_output",
		"Convolution Output", MS_NOT_AVAILABLE);

	SG_ADD(&m_convolution_output_gradients, "convolution_output_gradients",
		"Convolution Output Gradients", MS_NOT_AVAILABLE);
}
<commit_msg>fixed a memory leak in CNeuralConvolutionalLayer<commit_after>/*
 * Copyright (c) 2014, Shogun Toolbox Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:

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

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

#include <shogun/neuralnets/NeuralConvolutionalLayer.h>
#include <shogun/mathematics/Math.h>
#include <shogun/lib/SGVector.h>

using namespace shogun;

CNeuralConvolutionalLayer::CNeuralConvolutionalLayer() : CNeuralLayer()
{
	init();
}

CNeuralConvolutionalLayer::CNeuralConvolutionalLayer(
		EConvMapActivationFunction function,
		int32_t num_maps,
		int32_t radius_x, int32_t radius_y,
		int32_t pooling_width, int32_t pooling_height,
		int32_t stride_x, int32_t stride_y) : CNeuralLayer()
{
	init();
	m_num_maps = num_maps;
	m_radius_x = radius_x;
	m_radius_y = radius_y;
	m_pooling_width = pooling_width;
	m_pooling_height = pooling_height;
	m_stride_x = stride_x;
	m_stride_y = stride_y;
}

void CNeuralConvolutionalLayer::set_batch_size(int32_t batch_size)
{
	CNeuralLayer::set_batch_size(batch_size);

	if (autoencoder_position==NLAP_NONE)
		m_convolution_output = SGMatrix<float64_t>(m_num_maps*
			(m_input_width/m_stride_x)*(m_input_height/m_stride_y), batch_size);
	else
		m_convolution_output = SGMatrix<float64_t>(
			m_num_maps*m_input_width*m_input_height, batch_size);

	m_max_indices = SGMatrix<float64_t>(m_num_neurons, m_batch_size);

	m_convolution_output_gradients = SGMatrix<float64_t>(
		m_convolution_output.num_rows, m_convolution_output.num_cols);
}

void CNeuralConvolutionalLayer::initialize(CDynamicObjectArray* layers,
		SGVector< int32_t > input_indices)
{
	CNeuralLayer* first_input_layer =
		(CNeuralLayer*)layers->element(input_indices[0]);

	m_input_width = first_input_layer->get_width();
	m_input_height = first_input_layer->get_height();

	SG_UNREF(first_input_layer);

	if (autoencoder_position==NLAP_NONE)
	{
		m_width = m_input_width/(m_stride_x*m_pooling_width);
		m_height = m_input_height/(m_stride_y*m_pooling_height);
	}
	else
	{
		m_width = m_input_width;
		m_height = m_input_height;
	}

	m_num_neurons = m_width*m_height*m_num_maps;

	CNeuralLayer::initialize(layers, input_indices);

	m_input_num_channels = 0;
	for (int32_t l=0; l<input_indices.vlen; l++)
	{
		CNeuralLayer* layer =
			(CNeuralLayer*)layers->element(input_indices[l]);

		m_input_num_channels += layer->get_num_neurons()/(m_input_height*m_input_width);

		SG_UNREF(layer);
	}

	// one bias for each map and one weight matrix between each map in this
	// layer and each channel in the input layers
	m_num_parameters =
		m_num_maps*(1 + m_input_num_channels*(2*m_radius_x+1)*(2*m_radius_y+1));
}

void CNeuralConvolutionalLayer::initialize_parameters(SGVector<float64_t> parameters,
		SGVector<bool> parameter_regularizable,
		float64_t sigma)
{
	int32_t num_parameters_per_map =
		1 + m_input_num_channels*(2*m_radius_x+1)*(2*m_radius_y+1);

	for (int32_t m=0; m<m_num_maps; m++)
	{
		float64_t* map_params = parameters.vector+m*num_parameters_per_map;
		bool* map_param_regularizable =
			parameter_regularizable.vector+m*num_parameters_per_map;

		for (int32_t i=0; i<num_parameters_per_map; i++)
		{
			map_params[i] = CMath::normal_random(0.0, sigma);

			// turn off regularization for the bias, on for the rest of the parameters
			map_param_regularizable[i] = (i != 0);
		}
	}
}

void CNeuralConvolutionalLayer::compute_activations(
		SGVector<float64_t> parameters,
		CDynamicObjectArray* layers)
{
	int32_t num_parameters_per_map =
		1 + m_input_num_channels*(2*m_radius_x+1)*(2*m_radius_y+1);

	for (int32_t m=0; m<m_num_maps; m++)
	{
		SGVector<float64_t> map_params(
			parameters.vector+m*num_parameters_per_map,
			num_parameters_per_map, false);

		CConvolutionalFeatureMap map(m_input_width, m_input_height,
			m_radius_x, m_radius_y, m_stride_x, m_stride_y, m,
			m_activation_function, autoencoder_position);

		map.compute_activations(map_params, layers, m_input_indices,
			m_convolution_output);

		map.pool_activations(m_convolution_output,
			m_pooling_width, m_pooling_height, m_activations, m_max_indices);
	}
}

void CNeuralConvolutionalLayer::compute_gradients(
		SGVector<float64_t> parameters,
		SGMatrix<float64_t> targets,
		CDynamicObjectArray* layers,
		SGVector<float64_t> parameter_gradients)
{
	if (targets.num_rows != 0)
	{
		// sqaured error measure
		// local_gradients = activations-targets
		int32_t length = m_num_neurons*m_batch_size;
		for (int32_t i=0; i<length; i++)
			m_activation_gradients[i] = (m_activations[i]-targets[i])/m_batch_size;
	}

	if (dropout_prop>0.0)
	{
		int32_t len = m_num_neurons*m_batch_size;
		for (int32_t i=0; i<len; i++)
			m_activation_gradients[i] *= m_dropout_mask[i];
	}

	// compute the pre-pooling activation gradients
	m_convolution_output_gradients.zero();
	for (int32_t i=0; i<m_num_neurons; i++)
		for (int32_t j=0; j<m_batch_size; j++)
			if (m_max_indices(i,j)!=-1.0)
				m_convolution_output_gradients(m_max_indices(i,j),j) =
					m_activation_gradients(i,j);

	int32_t num_parameters_per_map =
		1 + m_input_num_channels*(2*m_radius_x+1)*(2*m_radius_y+1);

	for (int32_t m=0; m<m_num_maps; m++)
	{
		SGVector<float64_t> map_params(
			parameters.vector+m*num_parameters_per_map,
			num_parameters_per_map, false);

		SGVector<float64_t> map_gradients(
			parameter_gradients.vector+m*num_parameters_per_map,
			num_parameters_per_map, false);

		CConvolutionalFeatureMap map(m_input_width, m_input_height,
			m_radius_x, m_radius_y, m_stride_x, m_stride_y, m,
			m_activation_function, autoencoder_position);

		map.compute_gradients(map_params, m_convolution_output,
			m_convolution_output_gradients, layers,
			m_input_indices, map_gradients);
	}
}

float64_t CNeuralConvolutionalLayer::compute_error(SGMatrix<float64_t> targets)
{
	// error = 0.5*(sum(targets-activations)^2)/batch_size
	float64_t sum = 0;
	int32_t length = m_num_neurons*m_batch_size;
	for (int32_t i=0; i<length; i++)
		sum += (targets[i]-m_activations[i])*(targets[i]-m_activations[i]);
	sum *= (0.5/m_batch_size);
	return sum;
}

void CNeuralConvolutionalLayer::enforce_max_norm(SGVector<float64_t> parameters,
		float64_t max_norm)
{
	int32_t num_weights = (2*m_radius_x+1)*(2*m_radius_y+1);

	int32_t num_parameters_per_map = 1 + m_input_num_channels*num_weights;

	for (int32_t offset=1; offset<parameters.vlen; offset+=num_parameters_per_map)
	{
		float64_t* weights = parameters.vector+offset;

		float64_t norm =
				SGVector<float64_t>::twonorm(weights, num_weights);

		if (norm > max_norm)
		{
			float64_t multiplier = max_norm/norm;
			for (int32_t i=0; i<num_weights; i++)
				weights[i] *= multiplier;
		}
	}
}

void CNeuralConvolutionalLayer::init()
{
	m_num_maps = 1;
	m_input_width = 0;
	m_input_height = 0;
	m_input_num_channels = 0;
	m_radius_x = 0;
	m_radius_y = 0;
	m_pooling_width = 1;
	m_pooling_height = 1;
	m_stride_x = 1;
	m_stride_y = 1;
	m_activation_function = CMAF_IDENTITY;

	SG_ADD(&m_num_maps, "num_maps", "Number of maps", MS_NOT_AVAILABLE);
	SG_ADD(&m_input_width, "input_width", "Input Width", MS_NOT_AVAILABLE);
	SG_ADD(&m_input_height, "input_height", "Input Height", MS_NOT_AVAILABLE);
	SG_ADD(&m_input_num_channels, "input_num_channels", "Input's number of channels",
		MS_NOT_AVAILABLE);
	SG_ADD(&m_radius_x, "radius_x", "X Radius", MS_NOT_AVAILABLE);
	SG_ADD(&m_radius_y, "radius_y", "Y Radius", MS_NOT_AVAILABLE);
	SG_ADD(&m_pooling_width, "pooling_width", "Pooling Width", MS_NOT_AVAILABLE);
	SG_ADD(&m_pooling_height, "pooling_height", "Pooling Height", MS_NOT_AVAILABLE);
	SG_ADD(&m_stride_x, "stride_x", "X Stride", MS_NOT_AVAILABLE);
	SG_ADD(&m_stride_y, "stride_y", "Y Stride", MS_NOT_AVAILABLE);
	SG_ADD((machine_int_t*) &m_activation_function, "activation_function",
		"Activation Function", MS_NOT_AVAILABLE);

	SG_ADD(&m_convolution_output, "convolution_output",
		"Convolution Output", MS_NOT_AVAILABLE);

	SG_ADD(&m_convolution_output_gradients, "convolution_output_gradients",
		"Convolution Output Gradients", MS_NOT_AVAILABLE);
}
<|endoftext|>


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

#include <grpc/support/port_platform.h>

#include "src/core/lib/iomgr/port.h"
#ifdef GRPC_POSIX_SOCKET_RESOLVE_ADDRESS

#include <string.h>
#include <sys/types.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>

#include "src/core/lib/event_engine/default_event_engine.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/block_annotate.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/resolve_address_posix.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/transport/error_utils.h"

namespace grpc_core {
namespace {

class NativeDNSRequest {
 public:
  NativeDNSRequest(
      absl::string_view name, absl::string_view default_port,
      std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
          on_done)
      : name_(name), default_port_(default_port), on_done_(std::move(on_done)) {
    GRPC_CLOSURE_INIT(&request_closure_, DoRequestThread, this, nullptr);
    Executor::Run(&request_closure_, absl::OkStatus(), ExecutorType::RESOLVER);
  }

 private:
  // Callback to be passed to grpc Executor to asynch-ify
  // LookupHostnameBlocking
  static void DoRequestThread(void* rp, grpc_error_handle /*error*/) {
    NativeDNSRequest* r = static_cast<NativeDNSRequest*>(rp);
    auto result =
        GetDNSResolver()->LookupHostnameBlocking(r->name_, r->default_port_);
    // running inline is safe since we've already been scheduled on the executor
    r->on_done_(std::move(result));
    delete r;
  }

  const std::string name_;
  const std::string default_port_;
  const std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
      on_done_;
  grpc_closure request_closure_;
};

}  // namespace

DNSResolver::TaskHandle NativeDNSResolver::LookupHostname(
    std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
        on_done,
    absl::string_view name, absl::string_view default_port,
    Duration /* timeout */, grpc_pollset_set* /* interested_parties */,
    absl::string_view /* name_server */) {
  // self-deleting class
  new NativeDNSRequest(name, default_port, std::move(on_done));
  return kNullHandle;
}

absl::StatusOr<std::vector<grpc_resolved_address>>
NativeDNSResolver::LookupHostnameBlocking(absl::string_view name,
                                          absl::string_view default_port) {
  ExecCtx exec_ctx;
  struct addrinfo hints;
  struct addrinfo *result = nullptr, *resp;
  int s;
  size_t i;
  grpc_error_handle err;
  std::vector<grpc_resolved_address> addresses;
  std::string host;
  std::string port;
  // parse name, splitting it into host and port parts
  SplitHostPort(name, &host, &port);
  if (host.empty()) {
    err = grpc_error_set_str(GRPC_ERROR_CREATE("unparseable host:port"),
                             StatusStrProperty::kTargetAddress, name);
    goto done;
  }
  if (port.empty()) {
    if (default_port.empty()) {
      err = grpc_error_set_str(GRPC_ERROR_CREATE("no port in name"),
                               StatusStrProperty::kTargetAddress, name);
      goto done;
    }
    port = std::string(default_port);
  }
  // Call getaddrinfo
  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;     /* ipv4 or ipv6 */
  hints.ai_socktype = SOCK_STREAM; /* stream socket */
  hints.ai_flags = AI_PASSIVE;     /* for wildcard IP address */
  GRPC_SCHEDULING_START_BLOCKING_REGION;
  s = getaddrinfo(host.c_str(), port.c_str(), &hints, &result);
  GRPC_SCHEDULING_END_BLOCKING_REGION;
  if (s != 0) {
    // Retry if well-known service name is recognized
    const char* svc[][2] = {{"http", "80"}, {"https", "443"}};
    for (i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
      if (port == svc[i][0]) {
        GRPC_SCHEDULING_START_BLOCKING_REGION;
        s = getaddrinfo(host.c_str(), svc[i][1], &hints, &result);
        GRPC_SCHEDULING_END_BLOCKING_REGION;
        break;
      }
    }
  }
  if (s != 0) {
    err = grpc_error_set_str(
        grpc_error_set_str(
            grpc_error_set_str(
                grpc_error_set_int(GRPC_ERROR_CREATE(gai_strerror(s)),
                                   StatusIntProperty::kErrorNo, s),
                StatusStrProperty::kOsError, gai_strerror(s)),
            StatusStrProperty::kSyscall, "getaddrinfo"),
        StatusStrProperty::kTargetAddress, name);
    goto done;
  }
  // Success path: fill in addrs
  for (resp = result; resp != nullptr; resp = resp->ai_next) {
    grpc_resolved_address addr;
    memcpy(&addr.addr, resp->ai_addr, resp->ai_addrlen);
    addr.len = resp->ai_addrlen;
    addresses.push_back(addr);
  }
  err = absl::OkStatus();
done:
  if (result) {
    freeaddrinfo(result);
  }
  if (err.ok()) {
    return addresses;
  }
  auto error_result = grpc_error_to_absl_status(err);
  return error_result;
}

DNSResolver::TaskHandle NativeDNSResolver::LookupSRV(
    std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
        on_resolved,
    absl::string_view /* name */, Duration /* timeout */,
    grpc_pollset_set* /* interested_parties */,
    absl::string_view /* name_server */) {
  grpc_event_engine::experimental::GetDefaultEventEngine()->Run([on_resolved] {
    ApplicationCallbackExecCtx app_exec_ctx;
    ExecCtx exec_ctx;
    on_resolved(absl::UnimplementedError(
        "The Native resolver does not support looking up SRV records"));
  });
  return {-1, -1};
};

DNSResolver::TaskHandle NativeDNSResolver::LookupTXT(
    std::function<void(absl::StatusOr<std::string>)> on_resolved,
    absl::string_view /* name */, Duration /* timeout */,
    grpc_pollset_set* /* interested_parties */,
    absl::string_view /* name_server */) {
  // Not supported
  grpc_event_engine::experimental::GetDefaultEventEngine()->Run([on_resolved] {
    ApplicationCallbackExecCtx app_exec_ctx;
    ExecCtx exec_ctx;
    on_resolved(absl::UnimplementedError(
        "The Native resolver does not support looking up TXT records"));
  });
  return {-1, -1};
};

bool NativeDNSResolver::Cancel(TaskHandle /*handle*/) { return false; }

}  // namespace grpc_core

#endif
<commit_msg>[event_engine] Move DNS resolution executor usage to event engine (#31230)<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <grpc/support/port_platform.h>

#include "src/core/lib/iomgr/port.h"
#ifdef GRPC_POSIX_SOCKET_RESOLVE_ADDRESS

#include <string.h>
#include <sys/types.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>

#include "src/core/lib/event_engine/default_event_engine.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/gprpp/thd.h"
#include "src/core/lib/iomgr/block_annotate.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/resolve_address_posix.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/transport/error_utils.h"

namespace grpc_core {
namespace {

void NativeDNSRequest(
    std::string name, std::string default_port,
    std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
        on_done) {
  grpc_event_engine::experimental::GetDefaultEventEngine()->Run(
      [name = std::move(name), default_port = std::move(default_port),
       on_done = std::move(on_done)]() mutable {
        ApplicationCallbackExecCtx callback_exec_ctx;
        ExecCtx exec_ctx;
        auto result =
            GetDNSResolver()->LookupHostnameBlocking(name, default_port);
        // running inline is safe since we've already been scheduled on the
        // executor
        on_done(std::move(result));
      });
}

}  // namespace

DNSResolver::TaskHandle NativeDNSResolver::LookupHostname(
    std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
        on_done,
    absl::string_view name, absl::string_view default_port,
    Duration /* timeout */, grpc_pollset_set* /* interested_parties */,
    absl::string_view /* name_server */) {
  NativeDNSRequest(std::string(name), std::string(default_port),
                   std::move(on_done));
  return kNullHandle;
}

absl::StatusOr<std::vector<grpc_resolved_address>>
NativeDNSResolver::LookupHostnameBlocking(absl::string_view name,
                                          absl::string_view default_port) {
  ExecCtx exec_ctx;
  struct addrinfo hints;
  struct addrinfo *result = nullptr, *resp;
  int s;
  size_t i;
  grpc_error_handle err;
  std::vector<grpc_resolved_address> addresses;
  std::string host;
  std::string port;
  // parse name, splitting it into host and port parts
  SplitHostPort(name, &host, &port);
  if (host.empty()) {
    err = grpc_error_set_str(GRPC_ERROR_CREATE("unparseable host:port"),
                             StatusStrProperty::kTargetAddress, name);
    goto done;
  }
  if (port.empty()) {
    if (default_port.empty()) {
      err = grpc_error_set_str(GRPC_ERROR_CREATE("no port in name"),
                               StatusStrProperty::kTargetAddress, name);
      goto done;
    }
    port = std::string(default_port);
  }
  // Call getaddrinfo
  memset(&hints, 0, sizeof(hints));
  hints.ai_family = AF_UNSPEC;     /* ipv4 or ipv6 */
  hints.ai_socktype = SOCK_STREAM; /* stream socket */
  hints.ai_flags = AI_PASSIVE;     /* for wildcard IP address */
  GRPC_SCHEDULING_START_BLOCKING_REGION;
  s = getaddrinfo(host.c_str(), port.c_str(), &hints, &result);
  GRPC_SCHEDULING_END_BLOCKING_REGION;
  if (s != 0) {
    // Retry if well-known service name is recognized
    const char* svc[][2] = {{"http", "80"}, {"https", "443"}};
    for (i = 0; i < GPR_ARRAY_SIZE(svc); i++) {
      if (port == svc[i][0]) {
        GRPC_SCHEDULING_START_BLOCKING_REGION;
        s = getaddrinfo(host.c_str(), svc[i][1], &hints, &result);
        GRPC_SCHEDULING_END_BLOCKING_REGION;
        break;
      }
    }
  }
  if (s != 0) {
    err = grpc_error_set_str(
        grpc_error_set_str(
            grpc_error_set_str(
                grpc_error_set_int(GRPC_ERROR_CREATE(gai_strerror(s)),
                                   StatusIntProperty::kErrorNo, s),
                StatusStrProperty::kOsError, gai_strerror(s)),
            StatusStrProperty::kSyscall, "getaddrinfo"),
        StatusStrProperty::kTargetAddress, name);
    goto done;
  }
  // Success path: fill in addrs
  for (resp = result; resp != nullptr; resp = resp->ai_next) {
    grpc_resolved_address addr;
    memcpy(&addr.addr, resp->ai_addr, resp->ai_addrlen);
    addr.len = resp->ai_addrlen;
    addresses.push_back(addr);
  }
  err = absl::OkStatus();
done:
  if (result) {
    freeaddrinfo(result);
  }
  if (err.ok()) {
    return addresses;
  }
  auto error_result = grpc_error_to_absl_status(err);
  return error_result;
}

DNSResolver::TaskHandle NativeDNSResolver::LookupSRV(
    std::function<void(absl::StatusOr<std::vector<grpc_resolved_address>>)>
        on_resolved,
    absl::string_view /* name */, Duration /* timeout */,
    grpc_pollset_set* /* interested_parties */,
    absl::string_view /* name_server */) {
  grpc_event_engine::experimental::GetDefaultEventEngine()->Run([on_resolved] {
    ApplicationCallbackExecCtx app_exec_ctx;
    ExecCtx exec_ctx;
    on_resolved(absl::UnimplementedError(
        "The Native resolver does not support looking up SRV records"));
  });
  return {-1, -1};
};

DNSResolver::TaskHandle NativeDNSResolver::LookupTXT(
    std::function<void(absl::StatusOr<std::string>)> on_resolved,
    absl::string_view /* name */, Duration /* timeout */,
    grpc_pollset_set* /* interested_parties */,
    absl::string_view /* name_server */) {
  // Not supported
  grpc_event_engine::experimental::GetDefaultEventEngine()->Run([on_resolved] {
    ApplicationCallbackExecCtx app_exec_ctx;
    ExecCtx exec_ctx;
    on_resolved(absl::UnimplementedError(
        "The Native resolver does not support looking up TXT records"));
  });
  return {-1, -1};
};

bool NativeDNSResolver::Cancel(TaskHandle /*handle*/) { return false; }

}  // namespace grpc_core

#endif
<|endoftext|>


<commit_before>#include <powerset.hpp>

#include "helpers.hpp"

#include <vector>
#include <string>
#include <iterator>

#include "catch.hpp"

using iter::powerset;
using IntPermSet = std::multiset<std::multiset<int>>;

TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") {
    const std::vector<int> ns = {1, 2, 3};
    IntPermSet v;
    for (auto&& st : powerset(ns)) {
        v.emplace(std::begin(st), std::end(st));
    }

    const IntPermSet vc = { {}, {1}, {2}, {3,}, {1,2}, {1,3}, {2,3}, {1,2,3} };
    REQUIRE( v == vc );
}

TEST_CASE("powerset: empty sequence gives only empty set", "[powerset]") {
    const std::vector<int> ns = {};
    auto ps = powerset(ns);
    auto it = std::begin(ps);
    REQUIRE( std::begin(*it) == std::end(*it) ); // it's empty
    ++it;
    REQUIRE( it == std::end(ps) );
}

TEST_CASE("powerset: iterators can be compared", "[powerset]") {
    const std::vector<int> ns = {1, 2};
    auto p = powerset(ns);
    auto it = std::begin(p);
    REQUIRE( it == std::begin(p) );
    REQUIRE_FALSE( it != std::begin(p) );
    REQUIRE( it != std::end(p) );
    REQUIRE_FALSE( it == std::end(p) );
    ++it;
    REQUIRE_FALSE( it == std::begin(p) );
    REQUIRE( it != std::begin(p) );
    REQUIRE_FALSE( it == std::end(p) );
    REQUIRE( it != std::end(p) );
    ++it;
    ++it;
    ++it;
    REQUIRE( it == std::end(p) );
    REQUIRE_FALSE( it != std::end(p) );
}

TEST_CASE("powerset: binds to lvalues, moves rvalues", "[powerset]") {
    itertest::BasicIterable<int> bi{1, 2};
    SECTION("binds to lvalues") {
        powerset(bi);
        REQUIRE_FALSE(bi.was_moved_from());
    }
    SECTION("moves rvalues") {
        powerset(std::move(bi));
        REQUIRE(bi.was_moved_from());
    }
}

TEST_CASE("powerset: doesn't move or copy elements of iterable", "[powerset]"){
    constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}};
    for (auto&& st : powerset(arr)) {
        for (auto&& i : st) {
            (void)i;
        }
    }
}
<commit_msg>tests powerset iterator copy ctor<commit_after>#include <powerset.hpp>

#include "helpers.hpp"

#include <vector>
#include <string>
#include <iterator>

#include "catch.hpp"

using iter::powerset;
using IntPermSet = std::multiset<std::multiset<int>>;

TEST_CASE("powerset: basic test, [1, 2, 3]", "[powerset]") {
    const std::vector<int> ns = {1, 2, 3};
    IntPermSet v;
    for (auto&& st : powerset(ns)) {
        v.emplace(std::begin(st), std::end(st));
    }

    const IntPermSet vc = { {}, {1}, {2}, {3,}, {1,2}, {1,3}, {2,3}, {1,2,3} };
    REQUIRE( v == vc );
}

TEST_CASE("powerset: empty sequence gives only empty set", "[powerset]") {
    const std::vector<int> ns = {};
    auto ps = powerset(ns);
    auto it = std::begin(ps);
    REQUIRE( std::begin(*it) == std::end(*it) ); // it's empty
    ++it;
    REQUIRE( it == std::end(ps) );
}

TEST_CASE("powerset: iterators can be compared", "[powerset]") {
    std::vector<int> ns = {1, 2};
    auto p = powerset(ns);
    {
        auto it = std::begin(p);
        REQUIRE( it == std::begin(p) );
        REQUIRE_FALSE( it != std::begin(p) );
        REQUIRE( it != std::end(p) );
        REQUIRE_FALSE( it == std::end(p) );
        ++it;
        REQUIRE_FALSE( it == std::begin(p) );
        REQUIRE( it != std::begin(p) );
        REQUIRE_FALSE( it == std::end(p) );
        REQUIRE( it != std::end(p) );
        ++it;
        ++it;
        ++it;
        REQUIRE( it == std::end(p) );
    }

    ns.push_back(3);
    {
        auto it = std::begin(p);
        auto it2 = std::begin(p);
        std::advance(it, 4);
        std::advance(it2, 4);
        REQUIRE( it == it2 );
        ++it2;
        REQUIRE( it != it2 );
    }

}

TEST_CASE("powerset: iterator copy ctor is correct", "[powerset]") {
    // { {}, {1}, {2}, {1, 2} }
    std::vector<int> ns = {1, 2};
    auto p = powerset(ns);
    auto it = std::begin(p);
    auto it2(it);
    REQUIRE( it == it2 );
    ++it2;
    REQUIRE( it != it2 );
    REQUIRE( std::begin(*it) == std::end(*it) );
}

TEST_CASE("powerset: binds to lvalues, moves rvalues", "[powerset]") {
    itertest::BasicIterable<int> bi{1, 2};
    SECTION("binds to lvalues") {
        powerset(bi);
        REQUIRE_FALSE(bi.was_moved_from());
    }
    SECTION("moves rvalues") {
        powerset(std::move(bi));
        REQUIRE(bi.was_moved_from());
    }
}

TEST_CASE("powerset: doesn't move or copy elements of iterable", "[powerset]"){
    constexpr itertest::SolidInt arr[] = {{1}, {0}, {2}};
    for (auto&& st : powerset(arr)) {
        for (auto&& i : st) {
            (void)i;
        }
    }
}
<|endoftext|>