<commit_before>// $Id: constants.C,v 1.1 2000/05/04 18:30:55 oliver Exp $

#include <BALL/COMMON/constants.h>

namespace BALL
{
	namespace Constants
	{
		double EPSILON = 1e-6;
	}
}
<commit_msg>changed: constants are now extern const (problems with g++/Linux-alpha)<commit_after>// $Id: constants.C,v 1.2 2000/05/15 19:10:51 oliver Exp $

#include <BALL/COMMON/constants.h>

namespace BALL
{
	namespace Constants
	{
		// EPSILON (used fr comparisons)
		double EPSILON = 1e-6;

		// PI
		const double  PI = 3.14159265358979323846L;

		// Euler's number - base of the natural logarithm
		const double  E  = 2.718281828459045235L;

		//	Elementary charge.
		const double	ELEMENTARY_CHARGE = 1.60217738E-19L;  	 // C

		/// Elementary charge (alias)
		const double	e0								=	ELEMENTARY_CHARGE;

		// Electron mass.
		const double	ELECTRON_MASS   	= 9.1093897E-31L;   	 // kg

		// Proton mass.
		const double	PROTON_MASS     	= 1.6726230E-27L;   	 // kg

		// Neutron mass.
		const double	NEUTRON_MASS    	= 1.6749286E-27L;   	 // kg

		// Avogadro constant.
		const double	AVOGADRO        	= 6.0221367E+23L;   	 // 1 / mol

		// Avogadro constant (alias)
		const double	NA								= AVOGADRO;

		// Avogadro constant (alias)
		const double	MOL             	= AVOGADRO;

		// Boltzmann constant.
		const double	BOLTZMANN       	= 1.380657E-23L;  	   // J / K

		// Boltzmann constant (alias)
		const double	k	        				= BOLTZMANN;

		// Planck constant.
		const double	PLANCK 	         	= 6.6260754E-34L;      // J * sec

		// Planck constant (alias)
		const double	h       	   			= PLANCK;

		// Gas constant (= NA * k)
		const double	GAS_CONSTANT 	  	= NA * k;

		// Gas constant (alias)
		const double R 								= GAS_CONSTANT;

		// Faraday constant (= NA * e0)
		const double	FARADAY         	= NA * e0;

		// Faraday constant (alias)
		const double	F    							= FARADAY;

		// Bohr radius.
		const double	BOHR_RADIUS     	= 5.29177249E-11L;     // m

		// Bohr radius (alias)
		const double	a0     						= BOHR_RADIUS;

		//  the following values from:
		//  P.W.Atkins: Physical Chemistry, 5th ed., Oxford University Press, 1995

		// Vacuum permittivity.
		const double	VACUUM_PERMITTIVITY    	= 8.85419E-12L;     // C^2 / (J * m)

		// Vacuum permeability.
		const double	VACUUM_PERMEABILITY     = (4 * PI * 1E-7L);	// J s^2 / (C^2 * m)

		// Speed of light.
		const double	SPEED_OF_LIGHT          = 2.99792458E+8L;	  // m / s

		// Speed of Light (alias)
		const double	c												= SPEED_OF_LIGHT;

		// Gravitational constant.
		const double	GRAVITATIONAL_CONSTANT  = 6.67259E-11L;    	// N m^2 / kg^2

		// Fine structure constant.
		const double	FINE_STRUCTURE_CONSTANT = 7.29735E-3L;   		// 1

		// Degree per rad.
		const double	DEG_PER_RAD				= 57.2957795130823209L;

		// Rad per degree.
		const double	RAD_PER_DEG			 	= 0.0174532925199432957L;

		// mm per inch.
		const double	MM_PER_INCH 			= 25.4L;

		// m per foot.
		const double	M_PER_FOOT  			= 3.048L;

		// Joule per calorie
		const double	JOULE_PER_CAL     = 4.184;

		// Calories per Joule.
		const double	CAL_PER_JOULE     = (1 / 4.184);

	}
}
<|endoftext|>


<commit_before>/*
 * Flexisip, a flexible SIP proxy server with media capabilities.
 * Copyright (C) 2018  Belledonne Communications SARL, All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <algorithm>
#include <cstring>
#include <sstream>
#include <stdexcept>

#include "log/logmanager.hh"

#include "external-auth-module.hh"

using namespace std;

ExternalAuthModule::ExternalAuthModule(su_root_t *root, const std::string &domain, const std::string &algo) : FlexisipAuthModuleBase(root, domain, algo) {
	mEngine = nth_engine_create(root, TAG_END());
}

ExternalAuthModule::ExternalAuthModule(su_root_t *root, const std::string &domain, const std::string &algo, int nonceExpire) : FlexisipAuthModuleBase(root, domain, algo, nonceExpire) {
	mEngine = nth_engine_create(root, TAG_END());
}

ExternalAuthModule::~ExternalAuthModule() {
	nth_engine_destroy(mEngine);
}

void ExternalAuthModule::checkAuthHeader(FlexisipAuthStatus &as, msg_auth_t *credentials, auth_challenger_t const *ach) {
	try {
		auto &externalAs = dynamic_cast<ExternalAuthModule::Status &>(as);
		map<string, string> params = extractParameters(externalAs, *credentials);

		string uri;
		try {
			uri = mUriFormater.format(params);
		} catch (const invalid_argument &e) {
			ostringstream os;
			os << "cannot format HTTP URI: " << e.what();
			throw runtime_error(os.str());
		}

		auto *ctx = new HttpRequestCtx({*this, as});

		nth_client_t *request = nth_client_tcreate(mEngine,
			onHttpResponseCb,
			reinterpret_cast<nth_client_magic_t *>(ctx),
			http_method_get,
			"GET",
			URL_STRING_MAKE(uri.c_str()),
			TAG_END()
		);
		if (request == nullptr) {
			ostringstream os;
			os << "HTTP request for '" << uri << "' has failed";
			delete ctx;
			throw runtime_error(os.str());
		}
		SLOGD << "HTTP request [" << request << "] to '" << uri << "' successfully sent";
		as.status(100);
	} catch (const runtime_error &e) {
		SLOGE << e.what();
		onError(as);
	}
}

void ExternalAuthModule::loadPassword(const FlexisipAuthStatus &as) {
}

std::map<std::string, std::string> ExternalAuthModule::extractParameters(const Status &as, const msg_auth_t &credentials) const {
	map<string, string> params;

	for (int i = 0; credentials.au_params[i] != nullptr; i++) {
		const char *param = credentials.au_params[i];
		const char *equal = strchr(const_cast<char *>(param), '=');
		string key(param, equal-param);
		string value = equal+1;
		params[move(key)] = move(value);
	}

	params["scheme"] = credentials.au_scheme;
	params["method"] = as.method();
	params["from"] = as.fromHeader();
	params["sip-instance"] = as.sipInstance();
	params["domain"] = as.domain();
	return params;
}

void ExternalAuthModule::onHttpResponse(FlexisipAuthStatus &as, nth_client_t *request, const http_t *http) {
	shared_ptr<RequestSipEvent> ev;
	try {
		int sipCode = 0;
		string phrase;
		string reasonHeaderValue;
		string pAssertedIdentity;
		ostringstream os;

		if (http == nullptr) {
			os << "HTTP server responds with code " << nth_client_status(request);
			throw runtime_error(os.str());
		}

		int status = http->http_status->st_status;
		SLOGD << "HTTP response received [" << status << "]: " << endl << http->http_payload;
		if (status != 200) {
			os << "unhandled HTTP status code [" << status << "]";
			throw runtime_error(os.str());
		}

		string httpBody = toString(http->http_payload);
		if (httpBody.empty()) {
			os << "HTTP server answered with an empty body";
			throw runtime_error(os.str());
		}

		try {
			map<string, string> kv = parseHttpBody(httpBody);
			sipCode = stoi(kv["Status"]);
			phrase = move(kv["Phrase"]);
			reasonHeaderValue = move(kv["Reason"]);
			pAssertedIdentity = move(kv["P-Asserted-Identity"]);
		} catch (const logic_error &e) {
			os << "error while parsing HTTP body: " << e.what();
			throw runtime_error(os.str());
		}

		if (!validSipCode(sipCode) || reasonHeaderValue.empty()) {
			os << "invalid SIP code or reason";
			throw runtime_error(os.str());
		}

		auto &httpAuthStatus = dynamic_cast<ExternalAuthModule::Status &>(as);
		httpAuthStatus.status(sipCode == 200 ? 0 : sipCode);
		httpAuthStatus.phrase(su_strdup(as.home(), phrase.c_str()));
		httpAuthStatus.reason(reasonHeaderValue);
		httpAuthStatus.pAssertedIdentity(pAssertedIdentity);
		finish(as);
	} catch (const runtime_error &e) {
		SLOGE << "HTTP request [" << request << "]: " << e.what();
		onError(as);
	} catch (...) {
		if (request) nth_client_destroy(request);
		throw;
	}
	if (request) nth_client_destroy(request);
}

std::map<std::string, std::string> ExternalAuthModule::parseHttpBody(const std::string &body) const {
	istringstream is(body);
	ostringstream os;
	map<string, string> result;
	string line;

	do {
		getline(is, line);
		if (line.empty()) continue;

		auto column = find(line.cbegin(), line.cend(), ':');
		if (column == line.cend()) {
			os << "invalid line '" << line << "': missing column symbol";
			throw invalid_argument(os.str());
		}

		string &value = result[string(line.cbegin(), column)];
		auto valueStart = find_if_not(column+1, line.cend(), [](const char &c){return isspace(c) != 0;});
		if (valueStart == line.cend()) {
			os << "invalid line '" << line << "': missing value";
			throw invalid_argument(os.str());
		}

		value.assign(valueStart, line.cend());
	} while (!is.eof());
	return result;
}

int ExternalAuthModule::onHttpResponseCb(nth_client_magic_t *magic, nth_client_t *request, const http_t *http) noexcept {
	auto *ctx = reinterpret_cast<HttpRequestCtx *>(magic);
	ctx->am.onHttpResponse(ctx->as, request, http);
	delete ctx;
	return 0;
}

std::string ExternalAuthModule::toString(const http_payload_t *httpPayload) {
	if (httpPayload == nullptr || httpPayload->pl_data == nullptr || httpPayload->pl_len == 0) {
		return string();
	}
	return string(httpPayload->pl_data, httpPayload->pl_len);
}

bool ExternalAuthModule::validSipCode(int sipCode) {
	const auto it = find(sValidSipCodes.cbegin(), sValidSipCodes.cend(), sipCode);
	return (it != sValidSipCodes.cend());
}

std::array<int, 4> ExternalAuthModule::sValidSipCodes{{200, 401, 407, 403}};
<commit_msg>ExternalAuth: Make Reason header to be optional in the HTTP server response<commit_after>/*
 * Flexisip, a flexible SIP proxy server with media capabilities.
 * Copyright (C) 2018  Belledonne Communications SARL, All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <algorithm>
#include <cstring>
#include <sstream>
#include <stdexcept>

#include "log/logmanager.hh"

#include "external-auth-module.hh"

using namespace std;

ExternalAuthModule::ExternalAuthModule(su_root_t *root, const std::string &domain, const std::string &algo) : FlexisipAuthModuleBase(root, domain, algo) {
	mEngine = nth_engine_create(root, TAG_END());
}

ExternalAuthModule::ExternalAuthModule(su_root_t *root, const std::string &domain, const std::string &algo, int nonceExpire) : FlexisipAuthModuleBase(root, domain, algo, nonceExpire) {
	mEngine = nth_engine_create(root, TAG_END());
}

ExternalAuthModule::~ExternalAuthModule() {
	nth_engine_destroy(mEngine);
}

void ExternalAuthModule::checkAuthHeader(FlexisipAuthStatus &as, msg_auth_t *credentials, auth_challenger_t const *ach) {
	try {
		auto &externalAs = dynamic_cast<ExternalAuthModule::Status &>(as);
		map<string, string> params = extractParameters(externalAs, *credentials);

		string uri;
		try {
			uri = mUriFormater.format(params);
		} catch (const invalid_argument &e) {
			ostringstream os;
			os << "cannot format HTTP URI: " << e.what();
			throw runtime_error(os.str());
		}

		auto *ctx = new HttpRequestCtx({*this, as});

		nth_client_t *request = nth_client_tcreate(mEngine,
			onHttpResponseCb,
			reinterpret_cast<nth_client_magic_t *>(ctx),
			http_method_get,
			"GET",
			URL_STRING_MAKE(uri.c_str()),
			TAG_END()
		);
		if (request == nullptr) {
			ostringstream os;
			os << "HTTP request for '" << uri << "' has failed";
			delete ctx;
			throw runtime_error(os.str());
		}
		SLOGD << "HTTP request [" << request << "] to '" << uri << "' successfully sent";
		as.status(100);
	} catch (const runtime_error &e) {
		SLOGE << e.what();
		onError(as);
	}
}

void ExternalAuthModule::loadPassword(const FlexisipAuthStatus &as) {
}

std::map<std::string, std::string> ExternalAuthModule::extractParameters(const Status &as, const msg_auth_t &credentials) const {
	map<string, string> params;

	for (int i = 0; credentials.au_params[i] != nullptr; i++) {
		const char *param = credentials.au_params[i];
		const char *equal = strchr(const_cast<char *>(param), '=');
		string key(param, equal-param);
		string value = equal+1;
		params[move(key)] = move(value);
	}

	params["scheme"] = credentials.au_scheme;
	params["method"] = as.method();
	params["from"] = as.fromHeader();
	params["sip-instance"] = as.sipInstance();
	params["domain"] = as.domain();
	return params;
}

void ExternalAuthModule::onHttpResponse(FlexisipAuthStatus &as, nth_client_t *request, const http_t *http) {
	shared_ptr<RequestSipEvent> ev;
	try {
		int sipCode = 0;
		string phrase;
		string reasonHeaderValue;
		string pAssertedIdentity;
		ostringstream os;

		if (http == nullptr) {
			os << "HTTP server responds with code " << nth_client_status(request);
			throw runtime_error(os.str());
		}

		int status = http->http_status->st_status;
		SLOGD << "HTTP response received [" << status << "]: " << endl << http->http_payload;
		if (status != 200) {
			os << "unhandled HTTP status code [" << status << "]";
			throw runtime_error(os.str());
		}

		string httpBody = toString(http->http_payload);
		if (httpBody.empty()) {
			os << "HTTP server answered with an empty body";
			throw runtime_error(os.str());
		}

		try {
			map<string, string> kv = parseHttpBody(httpBody);
			sipCode = stoi(kv["Status"]);
			phrase = move(kv["Phrase"]);
			reasonHeaderValue = move(kv["Reason"]);
			pAssertedIdentity = move(kv["P-Asserted-Identity"]);
		} catch (const logic_error &e) {
			os << "error while parsing HTTP body: " << e.what();
			throw runtime_error(os.str());
		}

		if (!validSipCode(sipCode)) {
			os << "invalid SIP code";
			throw runtime_error(os.str());
		}

		auto &httpAuthStatus = dynamic_cast<ExternalAuthModule::Status &>(as);
		httpAuthStatus.status(sipCode == 200 ? 0 : sipCode);
		httpAuthStatus.phrase(su_strdup(as.home(), phrase.c_str()));
		httpAuthStatus.reason(reasonHeaderValue);
		httpAuthStatus.pAssertedIdentity(pAssertedIdentity);
		finish(as);
	} catch (const runtime_error &e) {
		SLOGE << "HTTP request [" << request << "]: " << e.what();
		onError(as);
	} catch (...) {
		if (request) nth_client_destroy(request);
		throw;
	}
	if (request) nth_client_destroy(request);
}

std::map<std::string, std::string> ExternalAuthModule::parseHttpBody(const std::string &body) const {
	istringstream is(body);
	ostringstream os;
	map<string, string> result;
	string line;

	do {
		getline(is, line);
		if (line.empty()) continue;

		auto column = find(line.cbegin(), line.cend(), ':');
		if (column == line.cend()) {
			os << "invalid line '" << line << "': missing column symbol";
			throw invalid_argument(os.str());
		}

		string &value = result[string(line.cbegin(), column)];
		auto valueStart = find_if_not(column+1, line.cend(), [](const char &c){return isspace(c) != 0;});
		if (valueStart == line.cend()) {
			os << "invalid line '" << line << "': missing value";
			throw invalid_argument(os.str());
		}

		value.assign(valueStart, line.cend());
	} while (!is.eof());
	return result;
}

int ExternalAuthModule::onHttpResponseCb(nth_client_magic_t *magic, nth_client_t *request, const http_t *http) noexcept {
	auto *ctx = reinterpret_cast<HttpRequestCtx *>(magic);
	ctx->am.onHttpResponse(ctx->as, request, http);
	delete ctx;
	return 0;
}

std::string ExternalAuthModule::toString(const http_payload_t *httpPayload) {
	if (httpPayload == nullptr || httpPayload->pl_data == nullptr || httpPayload->pl_len == 0) {
		return string();
	}
	return string(httpPayload->pl_data, httpPayload->pl_len);
}

bool ExternalAuthModule::validSipCode(int sipCode) {
	const auto it = find(sValidSipCodes.cbegin(), sValidSipCodes.cend(), sipCode);
	return (it != sValidSipCodes.cend());
}

std::array<int, 4> ExternalAuthModule::sValidSipCodes{{200, 401, 407, 403}};
<|endoftext|>


<commit_before>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010 Niko Sams <niko.sams@gmail.com>
//

#include "AltitudeProfile.h"
#include <GeoPainter.h>
#include <GeoSceneLayer.h>
#include <ViewportParams.h>
#include <routing/RoutingManager.h>
#include <routing/AlternativeRoutesModel.h>
#include <GeoDataDocument.h>
#include <MarbleDebug.h>
#include <KPlotWidget>
#include <KPlotObject>
#include <KPlotAxis>
#include <AltitudeModel.h>
#include <MarbleModel.h>
#include <GeoDataParser.h>
#include <QFile>

#include "MarbleGraphicsGridLayout.h"
#include "WidgetGraphicsItem.h"
#include <QLabel>
#include <QLayout>

using namespace Marble;

AltitudeProfile::AltitudeProfile(const QPointF& point, const QSizeF& size)
    : AbstractFloatItem(point, size), m_isInitialized(false)
{

}

QStringList AltitudeProfile::backendTypes() const
{
    return QStringList( "altitudeProfile" );
}

bool AltitudeProfile::isInitialized() const
{
    return m_isInitialized;
}

void AltitudeProfile::initialize()
{
    m_isInitialized = true;

    connect( marbleModel()->routingManager()->alternativeRoutesModel(), SIGNAL( currentRouteChanged( GeoDataDocument* ) ), SLOT( currentRouteChanged( GeoDataDocument* ) ) );
    connect( marbleModel()->routingManager()->alternativeRoutesModel(), SIGNAL( currentRouteChanged( GeoDataDocument* ) ), SLOT( currentRouteChanged( GeoDataDocument* ) ) );

    m_graph = new KPlotWidget();
    m_graph->setAntialiasing( true );
    m_graph->axis( KPlotWidget::TopAxis )->setVisible( false );
    m_graph->axis( KPlotWidget::RightAxis )->setVisible( false );
    m_graph->resetPlot();
    //m_graph->axis( KPlotWidget::LeftAxis )->setLabel( QString() );
    //m_graph->axis( KPlotWidget::LeftAxis )->setLabel(tr("Altitude"));
    m_graph->axis( KPlotWidget::BottomAxis )->setTickLabelsShown(false);

    m_plot = new KPlotObject(Qt::red, KPlotObject::Lines, 3);
    m_graph->addPlotObject(m_plot);
    m_graph->setMaximumSize( QSize( 300, 100 ) );
    m_graph->setMinimumSize( QSize( 300, 100 ) );

    m_stats = new QLabel("Stats");
//     setContentSize( QSize( 400, 100 ) );
    QWidget *w = new QWidget();
    w->setMaximumSize( QSize( 400, 100 ) );
    w->setMinimumSize( QSize( 400, 100 ) );
    QHBoxLayout* l = new QHBoxLayout;
    w->setLayout( l );
    l->addWidget( m_graph, 3 );
    l->addWidget( m_stats, 1 );

    m_widgetItem = new WidgetGraphicsItem( this );
    m_widgetItem->setWidget( w );

    MarbleGraphicsGridLayout *layout = new MarbleGraphicsGridLayout( 1, 1 );
    layout->addItem( m_widgetItem, 0, 0 );

    setLayout( layout );

#if 0
    GeoDataParser parser( GeoData_UNKNOWN );

    QFile file( "/home/niko/tracks/2011-06-12-mattighofen.gpx" );
    file.open( QIODevice::ReadOnly );
    Q_ASSERT( parser.read( &file ) );
    GeoDataDocument* document = static_cast<GeoDataDocument*>( parser.releaseDocument() );
    Q_ASSERT( document );
    file.close();
    GeoDataPlacemark* routePlacemark = document->placemarkList().first();
    qDebug() << routePlacemark->geometry()->geometryId();
    Q_ASSERT(routePlacemark->geometry()->geometryId() ==  GeoDataMultiGeometryId);
    GeoDataMultiGeometry* routeWaypoints = static_cast<GeoDataMultiGeometry*>(routePlacemark->geometry());
    qDebug() << "size" << routeWaypoints->size(); // << "length" << routeWaypoints->length( EARTH_RADIUS );
    for(int i=0; i < routeWaypoints->size(); ++i) {
        GeoDataGeometry* route2 = routeWaypoints->child(i);
        qDebug() << "route2.geometryId" << route2->geometryId();
        Q_ASSERT(route2->geometryId() == GeoDataLineStringId);
        GeoDataLineString* routeWaypoints2 = static_cast<GeoDataLineString*>(route2);
        qDebug() << "size" << routeWaypoints2->size() << "length" << routeWaypoints2->length(EARTH_RADIUS);
        qreal previousAlt = 0;
        qreal totalIncrease = 0;
        for(int j=0; j< routeWaypoints2->size(); ++j) {
            GeoDataCoordinates coordinate = routeWaypoints2->at( j );
            qDebug() << coordinate.latitude(Marble::GeoDataCoordinates::Degree) << coordinate.longitude(Marble::GeoDataCoordinates::Degree) << coordinate.altitude();
            if (previousAlt && coordinate.altitude() > previousAlt) {
                totalIncrease += coordinate.altitude() - previousAlt;
            }
            previousAlt = coordinate.altitude();
        }
        qDebug() << "totalIncrease" << totalIncrease << "vs. 254m von garmin gemessen";
    }
#endif
}
void AltitudeProfile::currentRouteChanged( GeoDataDocument* route )
{
    m_plot->clearPoints();

    qint32 minY = INT_MAX;
    qint32 maxY = 0;
    quint32 numDataPoints = 0;
    qDebug() << "*************************";

    GeoDataPlacemark* routePlacemark = route->placemarkList().first();
    Q_ASSERT(routePlacemark->geometry()->geometryId() ==  GeoDataLineStringId);
    GeoDataLineString* routeWaypoints = static_cast<GeoDataLineString*>(routePlacemark->geometry());
    qDebug() << routeWaypoints->length( EARTH_RADIUS );
    qreal totalIncrease = 0;
    qreal totalIncreaseAvg = 0;
    qreal totalDecreaseAvg = 0;
    qreal lastAltitude = -100000;
    qreal lastAvgAltitude = -100000;
    QList<qreal> allAltitudes;
    for(int i=1; i < routeWaypoints->size(); ++i) {
        GeoDataCoordinates coordinate = routeWaypoints->at( i );
        GeoDataCoordinates coordinatePrev = routeWaypoints->at( i - 1 );
        //qreal altitude = marbleModel()->altitudeModel()->height(coordinate.latitude(Marble::GeoDataCoordinates::Degree), coordinate.longitude(Marble::GeoDataCoordinates::Degree));
        QList<qreal> altitudes = marbleModel()->altitudeModel()->heightProfile(
            coordinatePrev.latitude(Marble::GeoDataCoordinates::Degree),
            coordinatePrev.longitude(Marble::GeoDataCoordinates::Degree),
            coordinate.latitude(Marble::GeoDataCoordinates::Degree),
            coordinate.longitude(Marble::GeoDataCoordinates::Degree)
        );
        foreach(const qreal altitude, altitudes) {
            qDebug() << "POINT" << numDataPoints << coordinate.longitude(Marble::GeoDataCoordinates::Degree) << coordinate.latitude(Marble::GeoDataCoordinates::Degree)
                    << "height" << altitude;
            allAltitudes << altitude;
            if ( allAltitudes.count() >= 10 ) {
                qreal avgAltitude = 0;
                for(int j=0; j<10; ++j) {
                    avgAltitude += allAltitudes.at(allAltitudes.count()-j-1);
                }
                avgAltitude = avgAltitude / 10;
                if (lastAvgAltitude != -100000 && avgAltitude > lastAvgAltitude) {
                    totalIncreaseAvg += avgAltitude-lastAvgAltitude;
                }
                if (lastAvgAltitude != -100000 && avgAltitude < lastAvgAltitude) {
                    totalDecreaseAvg -= avgAltitude-lastAvgAltitude;
                }
                lastAvgAltitude = avgAltitude;
            }
            if ( lastAltitude != -100000 && altitude > lastAltitude ) {
                totalIncrease += altitude - lastAltitude;
                qDebug() << "INCREASE +=" << altitude - lastAltitude << "totalIncrease is now" << totalIncrease;
            }

            double value = altitude;
            //qDebug() << "value" << value;
            m_plot->addPoint(numDataPoints++, value);
            if (value > maxY) maxY = value;
            if (value < minY) minY = value;
            lastAltitude = altitude;
        }
    }
    qDebug() << "TOTAL INCREASE" << totalIncrease;
    qDebug() << "TOTAL INCREASE AVG" << totalIncreaseAvg;

    m_graph->setLimits( 0, numDataPoints, minY - minY / 5, maxY + maxY / 5 );

    m_stats->setText( tr( "Gain:
%0m
Loss:
%1m" ).arg( totalIncreaseAvg ).arg( totalDecreaseAvg ) );
}

QIcon AltitudeProfile::icon() const
{
    return QIcon();
}

QString AltitudeProfile::description() const
{
    return tr( "This is a float item that displays the altitude profile of a track." );
}

QString AltitudeProfile::nameId() const
{
    return QString( "altitudeProfile" );
}

QString AltitudeProfile::guiString() const
{
    return tr( "&Altitude Profile" );
}

QString AltitudeProfile::name() const
{
    return QString( "Altitude Profile" );
}

Q_EXPORT_PLUGIN2( AltitudeProfile, Marble::AltitudeProfile )

#include "AltitudeProfile.moc"

<commit_msg>check for GeoDataFolder, sometimes a route is in one<commit_after>//
// This file is part of the Marble Desktop Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010 Niko Sams <niko.sams@gmail.com>
//

#include "AltitudeProfile.h"
#include <GeoPainter.h>
#include <GeoSceneLayer.h>
#include <ViewportParams.h>
#include <routing/RoutingManager.h>
#include <routing/AlternativeRoutesModel.h>
#include <GeoDataDocument.h>
#include <MarbleDebug.h>
#include <KPlotWidget>
#include <KPlotObject>
#include <KPlotAxis>
#include <AltitudeModel.h>
#include <MarbleModel.h>
#include <GeoDataParser.h>
#include <QFile>

#include "MarbleGraphicsGridLayout.h"
#include "WidgetGraphicsItem.h"
#include <QLabel>
#include <QLayout>
#include <GeoDataFolder.h>

using namespace Marble;

AltitudeProfile::AltitudeProfile(const QPointF& point, const QSizeF& size)
    : AbstractFloatItem(point, size), m_isInitialized(false)
{

}

QStringList AltitudeProfile::backendTypes() const
{
    return QStringList( "altitudeProfile" );
}

bool AltitudeProfile::isInitialized() const
{
    return m_isInitialized;
}

void AltitudeProfile::initialize()
{
    m_isInitialized = true;

    connect( marbleModel()->routingManager()->alternativeRoutesModel(), SIGNAL( currentRouteChanged( GeoDataDocument* ) ), SLOT( currentRouteChanged( GeoDataDocument* ) ) );
    connect( marbleModel()->routingManager()->alternativeRoutesModel(), SIGNAL( currentRouteChanged( GeoDataDocument* ) ), SLOT( currentRouteChanged( GeoDataDocument* ) ) );

    m_graph = new KPlotWidget();
    m_graph->setAntialiasing( true );
    m_graph->axis( KPlotWidget::TopAxis )->setVisible( false );
    m_graph->axis( KPlotWidget::RightAxis )->setVisible( false );
    m_graph->resetPlot();
    //m_graph->axis( KPlotWidget::LeftAxis )->setLabel( QString() );
    //m_graph->axis( KPlotWidget::LeftAxis )->setLabel(tr("Altitude"));
    m_graph->axis( KPlotWidget::BottomAxis )->setTickLabelsShown(false);

    m_plot = new KPlotObject(Qt::red, KPlotObject::Lines, 3);
    m_graph->addPlotObject(m_plot);
    m_graph->setMaximumSize( QSize( 300, 100 ) );
    m_graph->setMinimumSize( QSize( 300, 100 ) );

    m_stats = new QLabel("Stats");
//     setContentSize( QSize( 400, 100 ) );
    QWidget *w = new QWidget();
    w->setMaximumSize( QSize( 400, 100 ) );
    w->setMinimumSize( QSize( 400, 100 ) );
    QHBoxLayout* l = new QHBoxLayout;
    w->setLayout( l );
    l->addWidget( m_graph, 3 );
    l->addWidget( m_stats, 1 );

    m_widgetItem = new WidgetGraphicsItem( this );
    m_widgetItem->setWidget( w );

    MarbleGraphicsGridLayout *layout = new MarbleGraphicsGridLayout( 1, 1 );
    layout->addItem( m_widgetItem, 0, 0 );

    setLayout( layout );

#if 0
    GeoDataParser parser( GeoData_UNKNOWN );

    QFile file( "/home/niko/tracks/2011-06-12-mattighofen.gpx" );
    file.open( QIODevice::ReadOnly );
    Q_ASSERT( parser.read( &file ) );
    GeoDataDocument* document = static_cast<GeoDataDocument*>( parser.releaseDocument() );
    Q_ASSERT( document );
    file.close();
    GeoDataPlacemark* routePlacemark = document->placemarkList().first();
    qDebug() << routePlacemark->geometry()->geometryId();
    Q_ASSERT(routePlacemark->geometry()->geometryId() ==  GeoDataMultiGeometryId);
    GeoDataMultiGeometry* routeWaypoints = static_cast<GeoDataMultiGeometry*>(routePlacemark->geometry());
    qDebug() << "size" << routeWaypoints->size(); // << "length" << routeWaypoints->length( EARTH_RADIUS );
    for(int i=0; i < routeWaypoints->size(); ++i) {
        GeoDataGeometry* route2 = routeWaypoints->child(i);
        qDebug() << "route2.geometryId" << route2->geometryId();
        Q_ASSERT(route2->geometryId() == GeoDataLineStringId);
        GeoDataLineString* routeWaypoints2 = static_cast<GeoDataLineString*>(route2);
        qDebug() << "size" << routeWaypoints2->size() << "length" << routeWaypoints2->length(EARTH_RADIUS);
        qreal previousAlt = 0;
        qreal totalIncrease = 0;
        for(int j=0; j< routeWaypoints2->size(); ++j) {
            GeoDataCoordinates coordinate = routeWaypoints2->at( j );
            qDebug() << coordinate.latitude(Marble::GeoDataCoordinates::Degree) << coordinate.longitude(Marble::GeoDataCoordinates::Degree) << coordinate.altitude();
            if (previousAlt && coordinate.altitude() > previousAlt) {
                totalIncrease += coordinate.altitude() - previousAlt;
            }
            previousAlt = coordinate.altitude();
        }
        qDebug() << "totalIncrease" << totalIncrease << "vs. 254m von garmin gemessen";
    }
#endif
}
void AltitudeProfile::currentRouteChanged( GeoDataDocument* route )
{
    m_plot->clearPoints();

    qint32 minY = INT_MAX;
    qint32 maxY = 0;
    quint32 numDataPoints = 0;
    qDebug() << "*************************";

    GeoDataPlacemark* routePlacemark = 0;
    Q_ASSERT(route->size());
    if ( !route->placemarkList().count() ) {
        qDebug() << "no placemarks found?!";
        for(int i=0; i<route->size(); ++i) {
            qDebug() << "nodeType" << i << route->child( i )->nodeType();
            if ( dynamic_cast<GeoDataFolder*>( route->child( i ) ) ) {
                Q_ASSERT( static_cast<GeoDataFolder*>( route->child( i ) )->placemarkList().size() );
                routePlacemark = static_cast<GeoDataFolder*>( route->child( i ) )->placemarkList().first();
            }
        }
    } else {
        routePlacemark = route->placemarkList().first();
    }
    Q_ASSERT(routePlacemark);
    Q_ASSERT(routePlacemark->geometry()->geometryId() ==  GeoDataLineStringId);
    GeoDataLineString* routeWaypoints = static_cast<GeoDataLineString*>(routePlacemark->geometry());
    qDebug() << routeWaypoints->length( EARTH_RADIUS );
    qreal totalIncrease = 0;
    qreal totalIncreaseAvg = 0;
    qreal totalDecreaseAvg = 0;
    qreal lastAltitude = -100000;
    qreal lastAvgAltitude = -100000;
    QList<qreal> allAltitudes;
    for(int i=1; i < routeWaypoints->size(); ++i) {
        GeoDataCoordinates coordinate = routeWaypoints->at( i );
        GeoDataCoordinates coordinatePrev = routeWaypoints->at( i - 1 );
        //qreal altitude = marbleModel()->altitudeModel()->height(coordinate.latitude(Marble::GeoDataCoordinates::Degree), coordinate.longitude(Marble::GeoDataCoordinates::Degree));
        QList<qreal> altitudes = marbleModel()->altitudeModel()->heightProfile(
            coordinatePrev.latitude(Marble::GeoDataCoordinates::Degree),
            coordinatePrev.longitude(Marble::GeoDataCoordinates::Degree),
            coordinate.latitude(Marble::GeoDataCoordinates::Degree),
            coordinate.longitude(Marble::GeoDataCoordinates::Degree)
        );
        foreach(const qreal altitude, altitudes) {
            qDebug() << "POINT" << numDataPoints << coordinate.longitude(Marble::GeoDataCoordinates::Degree) << coordinate.latitude(Marble::GeoDataCoordinates::Degree)
                    << "height" << altitude;
            allAltitudes << altitude;
            if ( allAltitudes.count() >= 10 ) {
                qreal avgAltitude = 0;
                for(int j=0; j<10; ++j) {
                    avgAltitude += allAltitudes.at(allAltitudes.count()-j-1);
                }
                avgAltitude = avgAltitude / 10;
                if (lastAvgAltitude != -100000 && avgAltitude > lastAvgAltitude) {
                    totalIncreaseAvg += avgAltitude-lastAvgAltitude;
                }
                if (lastAvgAltitude != -100000 && avgAltitude < lastAvgAltitude) {
                    totalDecreaseAvg -= avgAltitude-lastAvgAltitude;
                }
                lastAvgAltitude = avgAltitude;
            }
            if ( lastAltitude != -100000 && altitude > lastAltitude ) {
                totalIncrease += altitude - lastAltitude;
                qDebug() << "INCREASE +=" << altitude - lastAltitude << "totalIncrease is now" << totalIncrease;
            }

            double value = altitude;
            //qDebug() << "value" << value;
            m_plot->addPoint(numDataPoints++, value);
            if (value > maxY) maxY = value;
            if (value < minY) minY = value;
            lastAltitude = altitude;
        }
    }
    qDebug() << "TOTAL INCREASE" << totalIncrease;
    qDebug() << "TOTAL INCREASE AVG" << totalIncreaseAvg;

    m_graph->setLimits( 0, numDataPoints, minY - minY / 5, maxY + maxY / 5 );

    m_stats->setText( tr( "Gain:
%0m
Loss:
%1m" ).arg( totalIncreaseAvg ).arg( totalDecreaseAvg ) );
}

QIcon AltitudeProfile::icon() const
{
    return QIcon();
}

QString AltitudeProfile::description() const
{
    return tr( "This is a float item that displays the altitude profile of a track." );
}

QString AltitudeProfile::nameId() const
{
    return QString( "altitudeProfile" );
}

QString AltitudeProfile::guiString() const
{
    return tr( "&Altitude Profile" );
}

QString AltitudeProfile::name() const
{
    return QString( "Altitude Profile" );
}

Q_EXPORT_PLUGIN2( AltitudeProfile, Marble::AltitudeProfile )

#include "AltitudeProfile.moc"

<|endoftext|>


<commit_before>#pragma once
#include "support/cpp14.hpp"
#include <string>
#include <algorithm>
#include <cctype>

#if defined(_MSC_VER) && _MSC_VER <= 1800 // a bit of a hack...
#define snprintf _snprintf
#endif

namespace fmt {

inline void print(const std::string& str, bool flush = false) {
    printf("%s", str.c_str());
    if (flush)
        fflush(stdout);
}

inline void println(const std::string& str, bool flush = false) {
    print(str);
    printf("\n");
    if (flush)
        fflush(stdout);
}

// specialize for desired class
inline std::string str(const std::string& s) { return s; }

namespace detail {
    inline const char* norm_arg(const std::string& x) { return x.c_str(); }

    template<class T> cpp14::enable_if_t<std::is_integral<T>::value, long> norm_arg(T x) { return x; }
    template<class T> cpp14::enable_if_t<std::is_floating_point<T>::value, double> norm_arg(T x) { return x; }
    template<class T> cpp14::enable_if_t<std::is_pointer<T>::value, T> norm_arg(T x) { return x; }

    template<class T> cpp14::enable_if_t<
        !std::is_integral<T>::value &&
        !std::is_floating_point<T>::value &&
        !std::is_pointer<T>::value,
        const T*
    >
    inline norm_arg(const T& x) { return &x; }

    template<class R, class P>
    inline auto norm_arg(const std::chrono::duration<R, P>& x) -> decltype(norm_arg(x.count())) {
        return norm_arg(x.count());
    }

    template<class T>
    inline std::string conversion_specifier(const T* t) { return ".0s" + str(*t); }
    inline constexpr char conversion_specifier(long) { return 'd'; }
    inline constexpr char conversion_specifier(double) { return 'f'; }
    inline constexpr char conversion_specifier(const char*) { return 's'; }

    template<class T> inline bool check_specifier(char) { return false; }
    template<> inline bool check_specifier<long>(char type) { return type == 'd' || type == 'i'; }
    template<> inline bool check_specifier<double>(char type) { return type == 'f' || type == 'g' || type == 'e'; }
    template<> inline bool check_specifier<const char*>(char type) { return type == 's'; }

    struct convert_and_check_format {
        template <class... Ts>
        convert_and_check_format(const std::string& fmt, const Ts&... ts)
            : _begin{fmt.begin()}, _end{fmt.end()}
        {
            format.reserve(fmt.size());
            convert(ts...);
        }

        const char* c_str() const { return format.c_str(); }

    private:
        using iter_t = std::string::const_iterator;

        iter_t append(iter_t from, const iter_t to) {
            for (; from != to; ++from) {
                if (*from == '}' && (from + 1) != to && *(from + 1) == '}')
                    continue; // only print one close brace "}}"

                format.push_back(*from);
                if (*from == '%') // escape % by doubling it
                    format.push_back('%');
            }
            return to;
        }

        void convert() {
            // no arguments left, we don't want to find any more format specifiers
            it = std::find(_begin, _end, '{');
            if (it != _end && it + 1 != _end) {
                ++it;
                if (*it == '{') { // skip double brace "{{"
                    append(_begin, it);
                    _begin = it + 1;
                }
                else {
                    throw std::logic_error{"Too many format specifiers."};
                }
            }

            append(_begin, _end); // copy everything that's left
        }

        template <class T, class... Ts>
        void convert(const T& t, const Ts&... ts) {
            // look for a *single* open brace
            do {
                it = std::find(_begin, _end, '{');
                if (it == _end || it + 1 == _end)
                    throw std::logic_error{"Too few format specifiers."};

                ++it;
                if (*it == '{') { // skip double brace "{{"
                    append(_begin, it);
                    _begin = it + 1;
                }
            } while (*it == '{');

            // copy everything before the open brace
            _begin = append(_begin, it - 1);

            // replace '{' with '%'
            format.push_back('%');

            // look for close brace
            it = std::find(_begin, _end, '}');
            if (it == _end)
                throw std::logic_error{"Unclosed brace fromat specifier."};

            _begin = std::find(_begin, it, ':');
            if (_begin == it || _begin + 1 == it) { // automatically deduce type
                format += detail::conversion_specifier(t);
            }
            else { // check type
                if (!detail::check_specifier<T>(*(it - 1)))
                    throw std::logic_error{"Invalid format specifier: " + std::string(it - 1, it)};

                format.append(_begin + 1, it);
            }

            _begin = it + 1;
            convert(ts...); // this is not recursion (calling different function template)
        }

    private:
        iter_t it, _begin;
        const iter_t _end;
        std::string format;
    };
}

template<class... Ts>
std::string format(std::string fmt, Ts&&... ts) {
    const auto new_fmt = detail::convert_and_check_format(fmt, detail::norm_arg(ts)...);

    auto size = 2 * fmt.size();
    do {
        fmt.resize(size + 1);
        auto ret = snprintf(&fmt[0], fmt.size(), new_fmt.c_str(), detail::norm_arg(ts)...);
        if (ret >= 0)
            size = ret;
        else
            throw std::runtime_error{"Error while using snprintf() in fmt::format()."};
    } while (size > fmt.size());

    fmt.resize(size);
    return fmt;
}

inline std::string with_suffix(int number) {
    // number to string with SI suffix, e.g.: 14226 -> 14.2k, 5395984 -> 5.4M
    if (number >= 1000000)
        return format("{:.1f}M", number / 1000000.0);
    else if (number > 1000)
        return format("{:.1f}k", number / 1000.0);
    else
        return std::to_string(number);
}

} // namespace fmt
<commit_msg>Fixed format() on VS2013<commit_after>#pragma once
#include "support/cpp14.hpp"
#include <string>
#include <algorithm>
#include <cctype>

#if defined(_MSC_VER) && _MSC_VER <= 1800 // VS2013 does not have a C99 compliant snprintf
# include <cstdarg>
# define snprintf c99_snprintf

inline int c99_snprintf(char* str, size_t size, const char* format, ...) {
    int count = -1;
    va_list ap;

    va_start(ap, format);
    if (size != 0)
        count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
    if (count == -1)
        count = _vscprintf(format, ap);
    va_end(ap);

    return count;
}
#endif

namespace fmt {

inline void print(const std::string& str, bool flush = false) {
    printf("%s", str.c_str());
    if (flush)
        fflush(stdout);
}

inline void println(const std::string& str, bool flush = false) {
    print(str);
    printf("\n");
    if (flush)
        fflush(stdout);
}

// specialize for desired class
inline std::string str(const std::string& s) { return s; }

namespace detail {
    inline const char* norm_arg(const std::string& x) { return x.c_str(); }

    template<class T> cpp14::enable_if_t<std::is_integral<T>::value, long> norm_arg(T x) { return x; }
    template<class T> cpp14::enable_if_t<std::is_floating_point<T>::value, double> norm_arg(T x) { return x; }
    template<class T> cpp14::enable_if_t<std::is_pointer<T>::value, T> norm_arg(T x) { return x; }

    template<class T> cpp14::enable_if_t<
        !std::is_integral<T>::value &&
        !std::is_floating_point<T>::value &&
        !std::is_pointer<T>::value,
        const T*
    >
    inline norm_arg(const T& x) { return &x; }

    template<class R, class P>
    inline auto norm_arg(const std::chrono::duration<R, P>& x) -> decltype(norm_arg(x.count())) {
        return norm_arg(x.count());
    }

    template<class T>
    inline std::string conversion_specifier(const T* t) { return ".0s" + str(*t); }
    inline constexpr char conversion_specifier(long) { return 'd'; }
    inline constexpr char conversion_specifier(double) { return 'f'; }
    inline constexpr char conversion_specifier(const char*) { return 's'; }

    template<class T> inline bool check_specifier(char) { return false; }
    template<> inline bool check_specifier<long>(char type) { return type == 'd' || type == 'i'; }
    template<> inline bool check_specifier<double>(char type) { return type == 'f' || type == 'g' || type == 'e'; }
    template<> inline bool check_specifier<const char*>(char type) { return type == 's'; }

    struct convert_and_check_format {
        template <class... Ts>
        convert_and_check_format(const std::string& fmt, const Ts&... ts)
            : _begin{fmt.begin()}, _end{fmt.end()}
        {
            format.reserve(fmt.size());
            convert(ts...);
        }

        const char* c_str() const { return format.c_str(); }

    private:
        using iter_t = std::string::const_iterator;

        iter_t append(iter_t from, const iter_t to) {
            for (; from != to; ++from) {
                if (*from == '}' && (from + 1) != to && *(from + 1) == '}')
                    continue; // only print one close brace "}}"

                format.push_back(*from);
                if (*from == '%') // escape % by doubling it
                    format.push_back('%');
            }
            return to;
        }

        void convert() {
            // no arguments left, we don't want to find any more format specifiers
            it = std::find(_begin, _end, '{');
            if (it != _end && it + 1 != _end) {
                ++it;
                if (*it == '{') { // skip double brace "{{"
                    append(_begin, it);
                    _begin = it + 1;
                }
                else {
                    throw std::logic_error{"Too many format specifiers."};
                }
            }

            append(_begin, _end); // copy everything that's left
        }

        template <class T, class... Ts>
        void convert(const T& t, const Ts&... ts) {
            // look for a *single* open brace
            do {
                it = std::find(_begin, _end, '{');
                if (it == _end || it + 1 == _end)
                    throw std::logic_error{"Too few format specifiers."};

                ++it;
                if (*it == '{') { // skip double brace "{{"
                    append(_begin, it);
                    _begin = it + 1;
                }
            } while (*it == '{');

            // copy everything before the open brace
            _begin = append(_begin, it - 1);

            // replace '{' with '%'
            format.push_back('%');

            // look for close brace
            it = std::find(_begin, _end, '}');
            if (it == _end)
                throw std::logic_error{"Unclosed brace fromat specifier."};

            _begin = std::find(_begin, it, ':');
            if (_begin == it || _begin + 1 == it) { // automatically deduce type
                format += detail::conversion_specifier(t);
            }
            else { // check type
                if (!detail::check_specifier<T>(*(it - 1)))
                    throw std::logic_error{"Invalid format specifier: " + std::string(it - 1, it)};

                format.append(_begin + 1, it);
            }

            _begin = it + 1;
            convert(ts...); // this is not recursion (calling different function template)
        }

    private:
        iter_t it, _begin;
        const iter_t _end;
        std::string format;
    };
}

template<class... Ts>
std::string format(std::string fmt, Ts&&... ts) {
    const auto new_fmt = detail::convert_and_check_format(fmt, detail::norm_arg(ts)...);

    auto size = 2 * fmt.size();
    do {
        fmt.resize(size + 1);
        auto ret = snprintf(&fmt[0], fmt.size(), new_fmt.c_str(), detail::norm_arg(ts)...);
        if (ret >= 0)
            size = ret;
        else
            throw std::runtime_error{"Error while using snprintf() in fmt::format()."};
    } while (size > fmt.size());

    fmt.resize(size);
    return fmt;
}

inline std::string with_suffix(int number) {
    // number to string with SI suffix, e.g.: 14226 -> 14.2k, 5395984 -> 5.4M
    if (number >= 1000000)
        return format("{:.1f}M", number / 1000000.0);
    else if (number > 1000)
        return format("{:.1f}k", number / 1000.0);
    else
        return std::to_string(number);
}

} // namespace fmt
<|endoftext|>


<commit_before>#ifndef LIBTEN_SHARED_POOL_HH
#define LIBTEN_SHARED_POOL_HH

#include "task/rendez.hh"
#include "ten/logging.hh"

#include <boost/call_traits.hpp>
#include <set>
#include <deque>
#include <memory>
#include <atomic>

namespace ten {

namespace detail {
    template <typename T> class scoped_resource;
}

//! thread and task safe pool of shared resources
//
//! useful for connection pools and other types of shared resources
template <typename ResourceT, typename ScopeT = detail::scoped_resource<ResourceT> >
class shared_pool {
public:
    // use this scoped_resource type to RAII resources from the pool
    typedef ScopeT scoped_resource;
    typedef std::deque<std::shared_ptr<ResourceT> > queue_type;
    typedef std::set<std::shared_ptr<ResourceT> > set_type;
    typedef std::function<std::shared_ptr<ResourceT> ()> alloc_func;
protected:
    template <typename TT> friend class detail::scoped_resource;

    struct pool_impl {
        qutex mut;
        rendez not_empty;
        queue_type q;
        set_type set;
        std::string name;
        alloc_func new_resource;
        ssize_t max;
    };

    std::mutex _mutex;
    std::shared_ptr<pool_impl> _m;

    std::shared_ptr<pool_impl> get_safe() {
#if 0
        return std::atomic_load(&_m);
#else
        std::lock_guard<std::mutex> lock(_mutex);
        return _m;
#endif
    }

    void set_safe(std::shared_ptr<pool_impl> &other) {
#if 0
        std::atomic_store(&_m, other);
#else

        std::lock_guard<std::mutex> lock(_mutex);
        _m = other;
#endif
    }

public:
    shared_pool(const std::string &name_,
            const alloc_func &alloc_,
            ssize_t max_ = -1)
    {
        std::shared_ptr<pool_impl> m = std::make_shared<pool_impl>();
        m->name = name_;
        m->new_resource = alloc_;
        m->max = max_;
        set_safe(m);
    }

    shared_pool(const shared_pool &) = delete;
    shared_pool &operator =(const shared_pool &) = delete;

    size_t size() {
        std::shared_ptr<pool_impl> m(get_safe());
        std::lock_guard<qutex> lk(m->mut);
        return m->set.size();
    }

    void clear() {
        std::shared_ptr<pool_impl> m(get_safe());
        std::lock_guard<qutex> lk(m->ut);
        m->q.clear();
        m->set.clear();
    }

    const std::string &name() {
        std::shared_ptr<pool_impl> m(get_safe());
        return m->name;
    }

protected:
    bool is_not_empty() {
        std::shared_ptr<pool_impl> m(get_safe());
        return !m->q.empty();
    }

    static std::shared_ptr<ResourceT> acquire(std::shared_ptr<pool_impl> &m) {
        std::unique_lock<qutex> lk(m->mut);
        return create_or_acquire_with_lock(m, lk);
    }

    // internal, does not lock mutex
    static std::shared_ptr<ResourceT> create_or_acquire_with_lock(std::shared_ptr<pool_impl> &m, std::unique_lock<qutex> &lk) {
        while (m->q.empty()) {
            if (m->max < 0 || m->set.size() < (size_t)m->max) {
                // need to create a new resource
                return add_new_resource(m, lk);
                break;
            } else {
                // can't create anymore we're at max, try waiting
                // we don't use a predicate here because
                // we might be woken up from destroy()
                // in which case we might not be at max anymore
                m->not_empty.sleep(lk);
            }
        }

        CHECK(!m->q.empty());
        // pop resource from front of queue
        std::shared_ptr<ResourceT> c = m->q.front();
        m->q.pop_front();
        CHECK(c) << "acquire shared resource failed in pool: " << m->name;
        return c;
    }

    static void release(std::shared_ptr<pool_impl> &m, std::shared_ptr<ResourceT> &c) {
        safe_lock<qutex> lk(m->mut);
        // don't add resource to queue if it was removed from _set
        if (m->set.count(c)) {
            m->q.push_front(c);
            m->not_empty.wakeup();
        }
    }

    static void destroy(std::shared_ptr<pool_impl> &m, std::shared_ptr<ResourceT> &c) {
        safe_lock<qutex> lk(m->mut);
        // remove bad resource
        DVLOG(4) << "shared_pool(" << m->name
            << ") destroy in set? " << m->set.count(c)
            << " : " << c << " rc: " << c.use_count();
        size_t count = m->set.erase(c);
        if (count) {
            LOG(WARNING) << "destroying shared resource from pool " << m->name;
        }
        typename queue_type::iterator i = std::find(m->q.begin(), m->q.end(), c);
        if (i!=m->q.end()) { m->q.erase(i); }

        c.reset();

        // give waiting threads a chance to allocate a new resource
        m->not_empty.wakeup();
    }

    static std::shared_ptr<ResourceT> add_new_resource(std::shared_ptr<pool_impl> &m, std::unique_lock<qutex> &lk) {
        std::shared_ptr<ResourceT> c;
        lk.unlock(); // unlock while newing resource
        try {
            c = m->new_resource();
            CHECK(c) << "new_resource failed for pool: " << m->name;
            DVLOG(4) << "inserting to shared_pool(" << m->name << "): " << c;
        } catch (std::exception &e) {
            LOG(ERROR) << "exception creating new resource for pool: " << m->name << " " << e.what();
            lk.lock();
            throw;
        }
        lk.lock(); // re-lock before inserting to set
        m->set.insert(c);
        return c;
    }

};

namespace detail {

// do not use this class directly, instead use your shared_pool<>::scoped_resource
template <typename T> class scoped_resource {
public:
    //typedef typename std::add_reference<shared_pool<T>>::type poolref;
    typedef typename boost::call_traits<shared_pool<T>>::reference poolref;
    typedef typename shared_pool<T>::pool_impl pool_impl;
protected:
    std::shared_ptr<pool_impl> _pool;
    std::shared_ptr<T> _c;
    bool _success;
public:
    explicit scoped_resource(poolref p)
        : _pool(p.get_safe()),
        _success(false)
    {
        _c = shared_pool<T>::acquire(_pool);
    }

    //! must call done() to return the resource to the pool
    //! otherwise we destroy it because a timeout or other exception
    //! could have occured causing the resource state to be in transition
    ~scoped_resource() {
        if (_success) {
            shared_pool<T>::release(_pool, _c);
        } else {
            shared_pool<T>::destroy(_pool, _c);
        }
    }

    void done() {
        DCHECK(!_success);
        _success = true;
    }

    T *operator->() {
        if (!_c) throw std::runtime_error("null pointer");
        return _c.get();
    }

};

} // end detail namespace

} // end namespace ten

#endif // LIBTEN_SHARED_POOL_HH
<commit_msg>fix weird name parsing conflict<commit_after>#ifndef LIBTEN_SHARED_POOL_HH
#define LIBTEN_SHARED_POOL_HH

#include "task/rendez.hh"
#include "ten/logging.hh"

#include <boost/call_traits.hpp>
#include <set>
#include <deque>
#include <memory>
#include <atomic>

namespace ten {

namespace detail {
    template <typename T> class scoped_resource;
}

//! thread and task safe pool of shared resources
//
//! useful for connection pools and other types of shared resources
template <typename ResourceT, typename ScopeT = detail::scoped_resource<ResourceT> >
class shared_pool {
public:
    // use this scoped_resource type to RAII resources from the pool
    typedef ScopeT scoped_resource;
    typedef std::deque<std::shared_ptr<ResourceT> > queue_type;
    typedef std::set<std::shared_ptr<ResourceT> > set_type;
    typedef std::function<std::shared_ptr<ResourceT> ()> alloc_func;
protected:
    template <typename TT> friend class detail::scoped_resource;

    struct pool_impl {
        qutex mut;
        rendez not_empty;
        queue_type q;
        set_type set;
        std::string name;
        alloc_func new_resource;
        ssize_t max_resources;
    };

    std::mutex _mutex;
    std::shared_ptr<pool_impl> _m;

    std::shared_ptr<pool_impl> get_safe() {
#if 0
        return std::atomic_load(&_m);
#else
        std::lock_guard<std::mutex> lock(_mutex);
        return _m;
#endif
    }

    void set_safe(std::shared_ptr<pool_impl> &other) {
#if 0
        std::atomic_store(&_m, other);
#else

        std::lock_guard<std::mutex> lock(_mutex);
        _m = other;
#endif
    }

public:
    shared_pool(const std::string &name_,
            const alloc_func &alloc_,
            ssize_t max_ = -1)
    {
        std::shared_ptr<pool_impl> m = std::make_shared<pool_impl>();
        m->name = name_;
        m->new_resource = alloc_;
        m->max_resources = max_;
        set_safe(m);
    }

    shared_pool(const shared_pool &) = delete;
    shared_pool &operator =(const shared_pool &) = delete;

    size_t size() {
        std::shared_ptr<pool_impl> m(get_safe());
        std::lock_guard<qutex> lk(m->mut);
        return m->set.size();
    }

    void clear() {
        std::shared_ptr<pool_impl> m(get_safe());
        std::lock_guard<qutex> lk(m->ut);
        m->q.clear();
        m->set.clear();
    }

    const std::string &name() {
        std::shared_ptr<pool_impl> m(get_safe());
        return m->name;
    }

protected:
    bool is_not_empty() {
        std::shared_ptr<pool_impl> m(get_safe());
        return !m->q.empty();
    }

    static std::shared_ptr<ResourceT> acquire(std::shared_ptr<pool_impl> &m) {
        std::unique_lock<qutex> lk(m->mut);
        return create_or_acquire_with_lock(m, lk);
    }

    // internal, does not lock mutex
    static std::shared_ptr<ResourceT> create_or_acquire_with_lock(std::shared_ptr<pool_impl> &m, std::unique_lock<qutex> &lk) {
        while (m->q.empty()) {
            if (m->max_resources < 0 || m->set.size() < (size_t)m->max_resources) {
                // need to create a new resource
                return add_new_resource(m, lk);
                break;
            } else {
                // can't create anymore we're at max, try waiting
                // we don't use a predicate here because
                // we might be woken up from destroy()
                // in which case we might not be at max anymore
                m->not_empty.sleep(lk);
            }
        }

        CHECK(!m->q.empty());
        // pop resource from front of queue
        std::shared_ptr<ResourceT> c = m->q.front();
        m->q.pop_front();
        CHECK(c) << "acquire shared resource failed in pool: " << m->name;
        return c;
    }

    static void release(std::shared_ptr<pool_impl> &m, std::shared_ptr<ResourceT> &c) {
        safe_lock<qutex> lk(m->mut);
        // don't add resource to queue if it was removed from _set
        if (m->set.count(c)) {
            m->q.push_front(c);
            m->not_empty.wakeup();
        }
    }

    static void destroy(std::shared_ptr<pool_impl> &m, std::shared_ptr<ResourceT> &c) {
        safe_lock<qutex> lk(m->mut);
        // remove bad resource
        DVLOG(4) << "shared_pool(" << m->name
            << ") destroy in set? " << m->set.count(c)
            << " : " << c << " rc: " << c.use_count();
        size_t count = m->set.erase(c);
        if (count) {
            LOG(WARNING) << "destroying shared resource from pool " << m->name;
        }
        typename queue_type::iterator i = std::find(m->q.begin(), m->q.end(), c);
        if (i!=m->q.end()) { m->q.erase(i); }

        c.reset();

        // give waiting threads a chance to allocate a new resource
        m->not_empty.wakeup();
    }

    static std::shared_ptr<ResourceT> add_new_resource(std::shared_ptr<pool_impl> &m, std::unique_lock<qutex> &lk) {
        std::shared_ptr<ResourceT> c;
        lk.unlock(); // unlock while newing resource
        try {
            c = m->new_resource();
            CHECK(c) << "new_resource failed for pool: " << m->name;
            DVLOG(4) << "inserting to shared_pool(" << m->name << "): " << c;
        } catch (std::exception &e) {
            LOG(ERROR) << "exception creating new resource for pool: " << m->name << " " << e.what();
            lk.lock();
            throw;
        }
        lk.lock(); // re-lock before inserting to set
        m->set.insert(c);
        return c;
    }

};

namespace detail {

// do not use this class directly, instead use your shared_pool<>::scoped_resource
template <typename T> class scoped_resource {
public:
    //typedef typename std::add_reference<shared_pool<T>>::type poolref;
    typedef typename boost::call_traits<shared_pool<T>>::reference poolref;
    typedef typename shared_pool<T>::pool_impl pool_impl;
protected:
    std::shared_ptr<pool_impl> _pool;
    std::shared_ptr<T> _c;
    bool _success;
public:
    explicit scoped_resource(poolref p)
        : _pool(p.get_safe()),
        _success(false)
    {
        _c = shared_pool<T>::acquire(_pool);
    }

    //! must call done() to return the resource to the pool
    //! otherwise we destroy it because a timeout or other exception
    //! could have occured causing the resource state to be in transition
    ~scoped_resource() {
        if (_success) {
            shared_pool<T>::release(_pool, _c);
        } else {
            shared_pool<T>::destroy(_pool, _c);
        }
    }

    void done() {
        DCHECK(!_success);
        _success = true;
    }

    T *operator->() {
        if (!_c) throw std::runtime_error("null pointer");
        return _c.get();
    }

};

} // end detail namespace

} // end namespace ten

#endif // LIBTEN_SHARED_POOL_HH
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
/// \file stream_io.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// Defines functions for stream input/output
//----------------------------------------------------------------------------
// Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>
// Created: 2016-02-26
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is a part of utxx open-source project.

Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>

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

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

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#pragma once

#include <iosfwd>
#include <utxx/convert.hpp>
#include <utxx/container/stack_container.hpp>

namespace utxx {

//------------------------------------------------------------------------------
/// Read \a a_cnt values from the input stream.
/// @param in       input stream.
/// @param a_output array of \a a_cnt double values.
/// @param a_fields array of \a a_cnt field positions (ascending order). If this
///                 value is NULL, the values are read from the input stream
///                 in consequitive order disregarding field positions.
/// @param a_cnt    count of values to read (must be > 0).
/// @param a_convert lambda used to convert a string value to type \a T:
///   const char* (const char* begin, const char* end, T& outout);
///   The function must return NULL if conversion is unsuccessful, or a pointer
///   past last successfully parsed character otherwise.
/// @return true if successfully read \a a_cnt values.
//------------------------------------------------------------------------------
template <typename T = double, int StrSize = 256, class Convert>
bool read_values(std::istream& in, T* a_output, int* a_fields, int a_cnt,
                 const Convert& a_convert)
{
    assert(a_cnt);

    basic_stack_string<StrSize> str;

    auto& line = str.container();

    if (a_fields == nullptr) {
        for (int i=0; i < a_cnt; ++i) {
            if (in.eof()) return false;
            in >> *a_output++;
        }
    }
    else if (!std::getline(in, line))
        return false;
    else {
        const char* p = &*line.begin();
        const char* e = &*line.end();

        int fld = 0;

        auto ws      = [](char c)     { return c == ' ' || c == '\t'; };
        auto skip_ws = [&p, e, &ws]() { while (ws(*p) && p != e) p++; };

        for (int i=0; i < a_cnt; ++i, ++a_fields, ++a_output) {
            while (p != e) {
                skip_ws();
                if (++fld == *a_fields)
                    break;
                while (!ws(*p) && p != e) p++;
            }

            if (fld != *a_fields)
                return false;

            p = a_convert(p, e, *a_output);

            if (!p)
                return false;
        }
    }

    return true;
}

} // namespace utxx<commit_msg>Fix issue of reading bad input<commit_after>//----------------------------------------------------------------------------
/// \file stream_io.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// Defines functions for stream input/output
//----------------------------------------------------------------------------
// Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>
// Created: 2016-02-26
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is a part of utxx open-source project.

Copyright (C) 2016 Serge Aleynikov <saleyn@gmail.com>

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

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

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#pragma once

#include <iosfwd>
#include <utxx/convert.hpp>
#include <utxx/container/stack_container.hpp>

namespace utxx {

//------------------------------------------------------------------------------
/// Read \a a_cnt values from the input stream.
/// @param in       input stream.
/// @param a_output array of \a a_cnt double values.
/// @param a_fields array of \a a_cnt field positions (ascending order). If this
///                 value is NULL, the values are read from the input stream
///                 in consequitive order disregarding field positions.
/// @param a_cnt    count of values to read (must be > 0).
/// @param a_convert lambda used to convert a string value to type \a T:
///   const char* (const char* begin, const char* end, T& outout);
///   The function must return NULL if conversion is unsuccessful, or a pointer
///   past last successfully parsed character otherwise.
/// @return true if successfully read \a a_cnt values.
//------------------------------------------------------------------------------
template <typename T = double, int StrSize = 256, class Convert>
bool read_values(std::istream& in, T* a_output, int* a_fields, int a_cnt,
                 const Convert& a_convert)
{
    assert(a_cnt);

    basic_stack_string<StrSize> str;

    auto& line = str.container();

    if (a_fields == nullptr) {
        for (int i=0; i < a_cnt; ++i) {
            if (in.eof())  return false;
            in >> *a_output++;
            if (in.fail()) {
                in.clear();
                std::getline(in, line);
                return false;
            }
        }
    }
    else if (!std::getline(in, line))
        return false;
    else {
        const char* p = &*line.begin();
        const char* e = &*line.end();

        int fld = 0;

        auto ws      = [](char c)     { return c == ' ' || c == '\t'; };
        auto skip_ws = [&p, e, &ws]() { while (ws(*p) && p != e) p++; };

        for (int i=0; i < a_cnt; ++i, ++a_fields, ++a_output) {
            while (p != e) {
                skip_ws();
                if (++fld == *a_fields)
                    break;
                while (!ws(*p) && p != e) p++;
            }

            if (fld != *a_fields)
                return false;

            p = a_convert(p, e, *a_output);

            if (!p)
                return false;
        }
    }

    return true;
}

} // namespace utxx<|endoftext|>


<commit_before>#ifndef VSMC_RNG_AESNI_HPP
#define VSMC_RNG_AESNI_HPP

#include <vsmc/rng/m128i.hpp>

#define VSMC_STATIC_ASSERT_RNG_AESNI_RESULT_TYPE(ResultType) \
    VSMC_STATIC_ASSERT(                                                      \
            (cxx11::is_same<ResultType, uint32_t>::value ||                  \
             cxx11::is_same<ResultType, uint64_t>::value),                   \
            USE_AESNIEngine_WITH_INTEGER_TYPE_OTHER_THAN_uint32_t_OR_uint64_t)

#define VSMC_STATIC_ASSERT_RNG_AESNI \
    VSMC_STATIC_ASSERT_RNG_AESNI_RESULT_TYPE(ResultType);

#define VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(N, val) \
    template <> struct AESNIRoundConstant< N > :                             \
        public cxx11::integral_constant<int, val > {};

namespace vsmc {

namespace internal {

template <std::size_t N> struct AESNIRoundConstant;

VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(0, 0x01)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(1, 0x02)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(2, 0x04)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(3, 0x08)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(4, 0x10)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(5, 0x20)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(6, 0x40)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(7, 0x80)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(8, 0x1B)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(9, 0x36)

} // namespace vsmc::internal

/// \brief AESNI RNG engine reimplemented
/// \ingroup R123RNG
///
/// \details
/// This is a reimplementation of the algorithm AES as described in [Parallel
/// Random Numbers: As Easy as 1, 2, 3][r123paper] and implemented in
/// [Random123][r123lib].
///
/// The implementation is almost identical to the original. Compared to
/// `r123:Engine<r123::AESNI4x32>`, when using the default constructor or the
/// one with a single seed, the output shall be exactly the same for the first
/// \f$2^32\f$ iterations. Further iterations may produce different results, as
/// vSMC increment the counter slightly differently, but it still cover the
/// same range and has the same period as the original. In addition, this
/// engine allows output of 64-bits integers.
template <typename ResultType>
class AESNIEngine
{
    static VSMC_CONSTEXPR const std::size_t R_ = 10;
    static VSMC_CONSTEXPR const std::size_t K_ =
        sizeof(__m128i) / sizeof(ResultType);

    public :

    typedef ResultType result_type;
    typedef StaticVector<ResultType, K_> ctr_type;
    typedef StaticVector<__m128i, R_ + 1> key_type;
    typedef StaticVector<ResultType, K_> ukey_type;

    explicit AESNIEngine (result_type s = 0) :
        pac_(_mm_setzero_si128()),
        tmp0_(pac_), tmp1_(pac_), tmp2_(pac_), remain_(0)
    {
        VSMC_STATIC_ASSERT_RNG_AESNI;
        seed(s);
    }

    template <typename SeedSeq>
    explicit AESNIEngine (SeedSeq &seq, typename cxx11::enable_if<
            !internal::is_seed_sequence<SeedSeq, ResultType>::value>::type * =
            VSMC_NULLPTR) :
        pac_(_mm_setzero_si128()),
        tmp0_(pac_), tmp1_(pac_), tmp2_(pac_), remain_(0)
    {
        VSMC_STATIC_ASSERT_RNG_AESNI;
        seed(seq);
    }

    void seed (result_type s)
    {
        ctr_.fill(0);
        ukey_type uk;
        uk.fill(0);
        uk.front() = s;
        ukey(uk);
        remain_ = 0;
    }

    template <typename SeedSeq>
    void seed (SeedSeq &seq, typename cxx11::enable_if<
            !internal::is_seed_sequence<SeedSeq, ResultType>::value>::type * =
            VSMC_NULLPTR)
    {
        ctr_.fill(0);
        ukey_type uk;
        seq.generate(uk.begin(), uk.end());
        ukey(uk);
        remain_ = 0;
    }

    const ctr_type &ctr () const {return ctr_;}

    const key_type &key () const {return key_;}

    void ctr (const ctr_type &c)
    {
        ctr_ = c;
        remain_ = 0;
    }

    void key (const key_type &k)
    {
        key_ = k;
        remain_ = 0;
    }

    void ukey (const ukey_type &uk)
    {
        internal::pack(uk, pac_);
        init_key(pac_);
        remain_ = 0;
    }

    /// \brief Same as operator() but return the __m128i type
    __m128i generate ()
    {
        internal::RngCounter<ResultType, K_>::increment(ctr_);
        pack();
        generate<0>(cxx11::true_type());
        remain_ = 0;

        return pac_;
    }

    result_type operator() ()
    {
        if (remain_ == 0) {
            generate();
            internal::unpack(pac_, res_);
            remain_ = K_;
        }

        return res_[--remain_];
    }

    void discard (std::size_t nskip)
    {
        if (nskip == 0)
            return;

        --nskip;
        internal::RngCounter<ResultType, K_>::increment(ctr_, nskip);
        remain_ = 0;
        operator()();
        nskip = nskip % K_;
        if (remain_ >= nskip) {
            remain_ -= nskip;
            return;
        }

        nskip -= remain_;
        remain_ = K_ - nskip;
    }

    static VSMC_CONSTEXPR const result_type _Min = 0;
    static VSMC_CONSTEXPR const result_type _Max = static_cast<result_type>(
            ~(static_cast<result_type>(0)));

    static VSMC_CONSTEXPR result_type min VSMC_MNE () {return _Min;}
    static VSMC_CONSTEXPR result_type max VSMC_MNE () {return _Max;}

    friend inline bool operator== (
            const AESNIEngine<ResultType> &eng1,
            const AESNIEngine<ResultType> &eng2)
    {
        if (eng1.ctr_ != eng2.ctr_)
            return false;

        if (eng1.res_ != eng2.res_)
            return false;

        for (std::size_t i = 0; i != key_type::size(); ++i)
            if (!internal::is_equal(eng1.key_[i], eng2.key_[i]))
                return false;

        return eng1.remain_ == eng2.remain_;
    }

    friend inline bool operator!= (
            const AESNIEngine<ResultType> &eng1,
            const AESNIEngine<ResultType> &eng2)
    {return !(eng1 == eng2);}

    template <typename CharT, typename Traits>
    friend inline std::basic_ostream<CharT, Traits> &operator<< (
            std::basic_ostream<CharT, Traits> &os,
            const AESNIEngine<ResultType> &eng)
    {
        if (os) os << eng.ctr_ << ' ';
        if (os) os << eng.res_ << ' ';
        for (std::size_t i = 0; i != key_type::size(); ++i) {
            internal::output_m128i(os, eng.key_[i]);
            if (os) os << ' ';
        }
        internal::output_m128i(os, eng.pac_);  if (os) os << ' ';
        internal::output_m128i(os, eng.tmp0_); if (os) os << ' ';
        internal::output_m128i(os, eng.tmp1_); if (os) os << ' ';
        internal::output_m128i(os, eng.tmp2_); if (os) os << ' ';
        if (os) os << eng.remain_;

        return os;
    }

    template <typename CharT, typename Traits>
    friend inline std::basic_istream<CharT, Traits> &operator>> (
            std::basic_istream<CharT, Traits> &is,
            AESNIEngine<ResultType> &eng)
    {
        AESNIEngine eng_tmp;
        if (is) is >> std::ws >> eng_tmp.ctr_;
        if (is) is >> std::ws >> eng_tmp.res_;
        for (std::size_t i = 0; i != key_type::size(); ++i)
            internal::input_m128i(is, eng_tmp.key_[i]);
        internal::input_m128i(is, eng_tmp.pac_);
        internal::input_m128i(is, eng_tmp.tmp0_);
        internal::input_m128i(is, eng_tmp.tmp1_);
        internal::input_m128i(is, eng_tmp.tmp2_);
        if (is) is >> std::ws >> eng_tmp.remain_;
        if (is) eng = eng_tmp;

        return is;
    }

    private :

    ctr_type ctr_;
    ctr_type res_;
    key_type key_;
    __m128i pac_;
    __m128i tmp0_;
    __m128i tmp1_;
    __m128i tmp2_;
    std::size_t remain_;

    void pack ()
    {
        internal::pack(ctr_, pac_);
        pac_ = _mm_xor_si128(pac_, key_.front());
    }

    template <std::size_t>
    void generate (cxx11::false_type)
    {pac_ = _mm_aesenclast_si128(pac_, key_.back());}

    template <std::size_t N>
    void generate (cxx11::true_type)
    {
        pac_ = _mm_aesenc_si128(pac_, key_[Position<N + 1>()]);
        generate<N + 1>(cxx11::integral_constant<bool, N + 2 < R_>());
    }

    void init_key(__m128i k)
    {
        tmp0_ = k;
        init_key<0>(cxx11::true_type());
    }

    template <std::size_t>
    void init_key (cxx11::false_type) {key_.back() = tmp0_;}

    template <std::size_t N>
    void init_key (cxx11::true_type)
    {
        key_[Position<N>()] = tmp0_;
        tmp1_ = _mm_aeskeygenassist_si128(tmp0_,
                internal::AESNIRoundConstant<N>::value);
        init_key_assit();
        init_key<N + 1>(cxx11::integral_constant<bool, N + 1 < R_>());
    }

    void init_key_assit ()
    {
        tmp1_ = _mm_shuffle_epi32 (tmp1_ ,0xFF);
        tmp2_ = _mm_slli_si128    (tmp0_, 0x04);
        tmp0_ = _mm_xor_si128     (tmp0_, tmp2_);
        tmp2_ = _mm_slli_si128    (tmp2_, 0x04);
        tmp0_ = _mm_xor_si128     (tmp0_, tmp2_);
        tmp2_ = _mm_slli_si128    (tmp2_, 0x04);
        tmp0_ = _mm_xor_si128     (tmp0_, tmp2_);
        tmp0_ = _mm_xor_si128     (tmp0_, tmp1_);
    }
}; // class AESNIEngine

/// \brief AESNI RNG engine returning 32-bits integers
/// \ingroup R123RNG
typedef AESNIEngine<uint32_t> AESNI4x32;

/// \brief AESNI RNG engine returning 64-bits integers
/// \ingroup R123RNG
typedef AESNIEngine<uint64_t> AESNI2x64;

/// \brief AESNI RNG engine returning 128-bits integers
/// \ingroup R123RNG
typedef AESNIEngine<__m128i>  AESNI1x128;

} // namespace vsmc

#endif // VSMC_RNG_AESNI_HPP
<commit_msg>AESNIEngine now can use multiple blocks<commit_after>#ifndef VSMC_RNG_AESNI_HPP
#define VSMC_RNG_AESNI_HPP

#include <vsmc/rng/m128i.hpp>

#define VSMC_STATIC_ASSERT_RNG_AESNI_RESULT_TYPE(ResultType) \
    VSMC_STATIC_ASSERT(                                                      \
            (cxx11::is_same<ResultType, uint32_t>::value ||                  \
             cxx11::is_same<ResultType, uint64_t>::value),                   \
            USE_AESNIEngine_WITH_INTEGER_TYPE_OTHER_THAN_uint32_t_OR_uint64_t)

#define VSMC_STATIC_ASSERT_RNG_AESNI_BLOCKS(Blocks) \
    VSMC_STATIC_ASSERT((Blocks > 0), USE_AESNIEngine_WITH_ZERO_BLOCKS)

#define VSMC_STATIC_ASSERT_RNG_AESNI \
    VSMC_STATIC_ASSERT_RNG_AESNI_RESULT_TYPE(ResultType);                    \
    VSMC_STATIC_ASSERT_RNG_AESNI_BLOCKS(Blocks);

#define VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(N, val) \
    template <> struct AESNIRoundConstant< N > :                             \
        public cxx11::integral_constant<int, val > {};

namespace vsmc {

namespace internal {

template <std::size_t N> struct AESNIRoundConstant;

VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(0, 0x01)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(1, 0x02)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(2, 0x04)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(3, 0x08)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(4, 0x10)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(5, 0x20)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(6, 0x40)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(7, 0x80)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(8, 0x1B)
VSMC_DEFINE_RNG_AESNI_ROUND_CONSTANT(9, 0x36)

} // namespace vsmc::internal

/// \brief AESNI RNG engine reimplemented
/// \ingroup R123RNG
///
/// \details
/// This is a reimplementation of the algorithm AES as described in [Parallel
/// Random Numbers: As Easy as 1, 2, 3][r123paper] and implemented in
/// [Random123][r123lib].
///
/// The implementation is almost identical to the original. Compared to
/// `r123:Engine<r123::AESNI4x32>`, when using the default constructor or the
/// one with a single seed, the output shall be exactly the same for the first
/// \f$2^32\f$ iterations. Further iterations may produce different results, as
/// vSMC increment the counter slightly differently, but it still cover the
/// same range and has the same period as the original. In addition, this
/// engine allows output of 64-bits integers.
template <typename ResultType, std::size_t Blocks = 1>
class AESNIEngine
{
    static VSMC_CONSTEXPR const std::size_t R_ = 10;
    static VSMC_CONSTEXPR const std::size_t K_ =
        sizeof(__m128i) / sizeof(ResultType);

    public :

    typedef ResultType result_type;
    typedef StaticVector<ResultType, K_> ctr_type;
    typedef StaticVector<__m128i, R_ + 1> key_type;
    typedef StaticVector<ResultType, K_> ukey_type;

    explicit AESNIEngine (result_type s = 0) :
        tmp0_(), tmp1_(), tmp2_(), remain_(0)
    {
        VSMC_STATIC_ASSERT_RNG_AESNI;
        seed(s);
    }

    template <typename SeedSeq>
    explicit AESNIEngine (SeedSeq &seq, typename cxx11::enable_if<
            !internal::is_seed_sequence<SeedSeq, ResultType>::value>::type * =
            VSMC_NULLPTR) : tmp0_(), tmp1_(), tmp2_(), remain_(0)
    {
        VSMC_STATIC_ASSERT_RNG_AESNI;
        seed(seq);
    }

    void seed (result_type s)
    {
        ctr_type c;
        c.fill(0);
        ctr_.fill(c);
        ukey_type uk;
        uk.fill(0);
        uk.front() = s;
        ukey(uk);
        remain_ = 0;
    }

    template <typename SeedSeq>
    void seed (SeedSeq &seq, typename cxx11::enable_if<
            !internal::is_seed_sequence<SeedSeq, ResultType>::value>::type * =
            VSMC_NULLPTR)
    {
        ctr_type c;
        c.fill(0);
        ctr_.fill(c);
        ukey_type uk;
        seq.generate(uk.begin(), uk.end());
        ukey(uk);
        remain_ = 0;
    }

    const ctr_type &ctr () const {return ctr_;}

    const key_type &key () const {return key_;}

    void ctr (const ctr_type &c)
    {
        ctr_.back() = c;
        remain_ = 0;
    }

    void key (const key_type &k)
    {
        key_ = k;
        remain_ = 0;
    }

    void ukey (const ukey_type &uk)
    {
        internal::pack(uk, pac_.front());
        init_key(pac_.front());
        remain_ = 0;
    }

    result_type operator() ()
    {
        if (remain_ == 0)
            generate();
        --remain_;

        return result<Blocks - 1>(
                cxx11::integral_constant<bool, 1 < Blocks>());
    }

    void discard (std::size_t nskip)
    {
        if (nskip == 0)
            return;

        --nskip;
        internal::RngCounter<ResultType, K_>::increment(ctr_, nskip);
        remain_ = 0;
        operator()();
        nskip = nskip % K_;
        if (remain_ >= nskip) {
            remain_ -= nskip;
            return;
        }

        nskip -= remain_;
        remain_ = K_ - nskip;
    }

    static VSMC_CONSTEXPR const result_type _Min = 0;
    static VSMC_CONSTEXPR const result_type _Max = static_cast<result_type>(
            ~(static_cast<result_type>(0)));

    static VSMC_CONSTEXPR result_type min VSMC_MNE () {return _Min;}
    static VSMC_CONSTEXPR result_type max VSMC_MNE () {return _Max;}

    friend inline bool operator== (
            const AESNIEngine<ResultType> &eng1,
            const AESNIEngine<ResultType> &eng2)
    {
        if (eng1.ctr_ != eng2.ctr_)
            return false;

        if (eng1.res_ != eng2.res_)
            return false;

        for (std::size_t i = 0; i != key_type::size(); ++i)
            if (!internal::is_equal(eng1.key_[i], eng2.key_[i]))
                return false;

        return eng1.remain_ == eng2.remain_;
    }

    friend inline bool operator!= (
            const AESNIEngine<ResultType> &eng1,
            const AESNIEngine<ResultType> &eng2)
    {return !(eng1 == eng2);}

    template <typename CharT, typename Traits>
    friend inline std::basic_ostream<CharT, Traits> &operator<< (
            std::basic_ostream<CharT, Traits> &os,
            const AESNIEngine<ResultType> &eng)
    {
        if (os) os << eng.ctr_ << ' ';
        if (os) os << eng.res_ << ' ';
        for (std::size_t i = 0; i != key_type::size(); ++i) {
            internal::output_m128i(os, eng.key_[i]);
            if (os) os << ' ';
        }
        internal::output_m128i(os, eng.pac_);  if (os) os << ' ';
        internal::output_m128i(os, eng.tmp0_); if (os) os << ' ';
        internal::output_m128i(os, eng.tmp1_); if (os) os << ' ';
        internal::output_m128i(os, eng.tmp2_); if (os) os << ' ';
        if (os) os << eng.remain_;

        return os;
    }

    template <typename CharT, typename Traits>
    friend inline std::basic_istream<CharT, Traits> &operator>> (
            std::basic_istream<CharT, Traits> &is,
            AESNIEngine<ResultType> &eng)
    {
        AESNIEngine eng_tmp;
        if (is) is >> std::ws >> eng_tmp.ctr_;
        if (is) is >> std::ws >> eng_tmp.res_;
        for (std::size_t i = 0; i != key_type::size(); ++i)
            internal::input_m128i(is, eng_tmp.key_[i]);
        internal::input_m128i(is, eng_tmp.pac_);
        internal::input_m128i(is, eng_tmp.tmp0_);
        internal::input_m128i(is, eng_tmp.tmp1_);
        internal::input_m128i(is, eng_tmp.tmp2_);
        if (is) is >> std::ws >> eng_tmp.remain_;
        if (is) eng = eng_tmp;

        return is;
    }

    private :

    StaticVector<ctr_type, Blocks> ctr_;
    StaticVector<ctr_type, Blocks> res_;
    key_type key_;
    StaticVector<__m128i, Blocks> pac_;
    __m128i tmp0_;
    __m128i tmp1_;
    __m128i tmp2_;
    std::size_t remain_;

    void increment ()
    {
        ctr_.front() = ctr_.back();
        internal::RngCounter<ResultType, K_>::increment(ctr_.front());
        increment<1>(cxx11::integral_constant<bool, 1 < Blocks>());
    }

    template <std::size_t> void increment (cxx11::false_type) {}

    template <std::size_t B>
    void increment (cxx11::true_type)
    {
        ctr_[Position<B>()] = ctr_[Position<B - 1>()];
        internal::RngCounter<ResultType, K_>::increment(ctr_[Position<B>()]);
        increment<B + 1>(cxx11::integral_constant<bool, B + 1 < Blocks>());
    }

    void pack ()
    {
        internal::pack(ctr_.front(), pac_.front());
        pack<1>(cxx11::integral_constant<bool, 1 < Blocks>());
        pac_.front() = _mm_xor_si128(pac_.front(), key_.front());
        pac_xor<1>(cxx11::integral_constant<bool, 1 < Blocks>());
    }

    template <std::size_t> void pack (cxx11::false_type) {}

    template <std::size_t B>
    void pack (cxx11::true_type)
    {
        internal::pack(ctr_[Position<B>()], pac_[Position<B>()]);
        pack<B + 1>(cxx11::integral_constant<bool, B + 1 < Blocks>());
    }

    template <std::size_t> void pac_xor (cxx11::false_type) {}

    template <std::size_t B>
    void pac_xor (cxx11::true_type)
    {
        pac_[Position<B>()] = _mm_xor_si128(pac_[Position<B>()], key_.front());
        pac_xor<B + 1>(cxx11::integral_constant<bool, B + 1 < Blocks>());
    }

    template <std::size_t> void unpack (cxx11::false_type) {}

    void unpack ()
    {
        internal::unpack(pac_.front(), res_.front());
        unpack<1>(cxx11::integral_constant<bool, 1 < Blocks>());
    }

    template <std::size_t B>
    void unpack (cxx11::true_type)
    {
        internal::unpack(pac_[Position<B>()], res_[Position<B>()]);
        unpack<B + 1>(cxx11::integral_constant<bool, B + 1 < Blocks>());
    }

    void generate ()
    {
        increment();
        pack();
        generate<0>(cxx11::true_type());
        unpack();
        remain_ = K_ * Blocks;
    }

    template <std::size_t>
    void generate (cxx11::false_type)
    {
        pac_.front() = _mm_aesenclast_si128(pac_.front(), key_.back());
        generate_last<1>(cxx11::integral_constant<bool, 1 < Blocks>());
    }

    template <std::size_t> void generate_last (cxx11::false_type) {}

    template <std::size_t B>
    void generate_last (cxx11::true_type)
    {
        pac_[Position<B>()] =
            _mm_aesenclast_si128(pac_[Position<B>()], key_.back());
        generate_last<B + 1>(cxx11::integral_constant<bool, B + 1 < Blocks>());
    }

    template <std::size_t N>
    void generate (cxx11::true_type)
    {
        pac_.front() = _mm_aesenc_si128(pac_.front(), key_[Position<N + 1>()]);
        generate_step<1, N>(cxx11::integral_constant<bool, 1 < Blocks>());
        generate<N + 1>(cxx11::integral_constant<bool, N + 2 < R_>());
    }

    template <std::size_t, std::size_t>
    void generate_step (cxx11::false_type) {}

    template <std::size_t B, std::size_t N>
    void generate_step (cxx11::true_type)
    {
        pac_[Position<B>()] =
            _mm_aesenc_si128(pac_[Position<B>()], key_[Position<N + 1>()]);
        generate_step<B + 1, N>(
                cxx11::integral_constant<bool, B + 1 < Blocks>());
    }

    template <std::size_t>
    result_type result (cxx11::false_type)
    {return res_.front()[remain_];}

    template <std::size_t R>
    result_type result (cxx11::true_type)
    {
        if (remain_ > R * K_)
            return res_[Position<R>()][remain_ - R * K_];
        return result<R - 1>(cxx11::integral_constant<bool, 0 < R>());
    }

    void init_key(__m128i k)
    {
        tmp0_ = k;
        init_key<0>(cxx11::true_type());
    }

    template <std::size_t>
    void init_key (cxx11::false_type) {key_.back() = tmp0_;}

    template <std::size_t N>
    void init_key (cxx11::true_type)
    {
        key_[Position<N>()] = tmp0_;
        tmp1_ = _mm_aeskeygenassist_si128(tmp0_,
                internal::AESNIRoundConstant<N>::value);
        init_key_assit();
        init_key<N + 1>(cxx11::integral_constant<bool, N + 1 < R_>());
    }

    void init_key_assit ()
    {
        tmp1_ = _mm_shuffle_epi32 (tmp1_ ,0xFF);
        tmp2_ = _mm_slli_si128    (tmp0_, 0x04);
        tmp0_ = _mm_xor_si128     (tmp0_, tmp2_);
        tmp2_ = _mm_slli_si128    (tmp2_, 0x04);
        tmp0_ = _mm_xor_si128     (tmp0_, tmp2_);
        tmp2_ = _mm_slli_si128    (tmp2_, 0x04);
        tmp0_ = _mm_xor_si128     (tmp0_, tmp2_);
        tmp0_ = _mm_xor_si128     (tmp0_, tmp1_);
    }
}; // class AESNIEngine

/// \brief AESNI RNG engine returning 32-bits integers with default blocks
/// \ingroup R123RNG
typedef AESNIEngine<uint32_t> AESNI4x32;

/// \brief AESNI RNG engine returning 64-bits integers with default blocks
/// \ingroup R123RNG
typedef AESNIEngine<uint64_t> AESNI2x64;

/// \brief AESNI RNG engine returning 128-bits integers with default blocks
/// \ingroup R123RNG
typedef AESNIEngine<__m128i>  AESNI1x128;

/// \brief AESNI RNG engine returning 32-bits integers with 1 block
/// \ingroup R123RNG
typedef AESNIEngine<uint32_t, 1> AESNI4x32_1;

/// \brief AESNI RNG engine returning 64-bits integers with 1 block
/// \ingroup R123RNG
typedef AESNIEngine<uint64_t, 1> AESNI2x64_1;

/// \brief AESNI RNG engine returning 128-bits integers with 1 block
/// \ingroup R123RNG
typedef AESNIEngine<__m128i, 1>  AESNI1x128_1;

/// \brief AESNI RNG engine returning 32-bits integers with 2 block
/// \ingroup R123RNG
typedef AESNIEngine<uint32_t, 2> AESNI4x32_2;

/// \brief AESNI RNG engine returning 64-bits integers with 2 block
/// \ingroup R123RNG
typedef AESNIEngine<uint64_t, 2> AESNI2x64_2;

/// \brief AESNI RNG engine returning 128-bits integers with 2 block
/// \ingroup R123RNG
typedef AESNIEngine<__m128i, 2>  AESNI1x128_2;

/// \brief AESNI RNG engine returning 32-bits integers with 4 block
/// \ingroup R123RNG
typedef AESNIEngine<uint32_t, 4> AESNI4x32_4;

/// \brief AESNI RNG engine returning 64-bits integers with 4 block
/// \ingroup R123RNG
typedef AESNIEngine<uint64_t, 4> AESNI2x64_4;

/// \brief AESNI RNG engine returning 128-bits integers with 4 block
/// \ingroup R123RNG
typedef AESNIEngine<__m128i, 4>  AESNI1x128_4;

} // namespace vsmc

#endif // VSMC_RNG_AESNI_HPP
<|endoftext|>