<commit_before>#include "rosenbrock.h"

#include <qmath.h>

namespace
{
	Rosenbrock instance;
}

RpnOperand Rosenbrock::calculate(FunctionCalculator *calculator, QList<RpnOperand> actualArguments)
{
	m_calculator = calculator;

	m_functionName = actualArguments[0].value.value<QString>();

	m_sourcePoint = actualArguments[1].value.value<QList<Number> >();
	if (m_calculator->functionArguments(m_functionName).size() != m_sourcePoint.size()) {
		THROW(EWrongParametersCount(QObject::tr("Source point"), m_calculator->functionArguments(m_functionName).size()));
	}

	m_stopValue = actualArguments[2].value.value<Number>();
	m_accelerationStep = actualArguments[3].value.value<Number>();
	m_decreaseStep = actualArguments[4].value.value<Number>();

	m_steps = actualArguments[5].value.value<QList<Number> >();
	if (m_calculator->functionArguments(m_functionName).size() != m_steps.size()) {
		THROW(EWrongParametersCount(QObject::tr("Coordinate steps"), m_calculator->functionArguments(m_functionName).size()));
	}

	m_wrongStepsNumber = actualArguments[6].value.value<Number>();

	// Set start directions
	for (int i = 0; i < m_sourcePoint.size(); i++) {
		m_directions << QList<Number>();
		for (int k = 0; k < m_sourcePoint.size(); k++) {
			if (k == i) {
				m_directions[i] << 1;
			}
			else {
				m_directions[i] << 0;
			}
		}
	}

	RpnOperand result;
	result.type = RpnOperandVector;
	result.value = QVariant::fromValue(findMinimum());
	return result;
}

QList<RpnArgument> Rosenbrock::requiredArguments()
{
	QList<RpnArgument> arguments;
	arguments
		// NOTE: QVariant() shows that number of arguments is not fixed, maybe there is other way
		<< RpnArgument(RpnOperandFunctionName, QString(), QVariant())
		<< RpnArgument(RpnOperandVector)
		<< RpnArgument(RpnOperandNumber)
		<< RpnArgument(RpnOperandNumber)
		<< RpnArgument(RpnOperandNumber)
		<< RpnArgument(RpnOperandVector)
		<< RpnArgument(RpnOperandNumber);

	return arguments;
}

QList<Number> Rosenbrock::findMinimum()
{
	QList<Number> firstCurrentPoint = m_sourcePoint;
	QList<Number> sourceSteps = m_steps;
	QList<Number> currentPoint = firstCurrentPoint;

	forever {
		forever {
			int failStepsCount = 0;
			for (int i = 0; i < currentPoint.size(); i++) {
				if (countFunction(increaseDirection(currentPoint, i)) < countFunction(currentPoint)) {
					currentPoint = increaseDirection(currentPoint, i);
					m_steps[i] = m_steps[i] * m_accelerationStep;
				}
				else {
					m_steps[i] = m_steps[i] * m_decreaseStep;
					failStepsCount++;
				}
			}

			if (countFunction(currentPoint) == countFunction(firstCurrentPoint)) {
				if (countFunction(currentPoint) < countFunction(m_sourcePoint)) {
					// Loop exit condition
					break;
				}
				else if (countFunction(currentPoint) == countFunction(m_sourcePoint)) {
					if (failStepsCount <= m_wrongStepsNumber) {
						bool isFinish = true;
						for (int i = 0; i < m_steps.size(); i++) {
							if (qAbs(m_steps[i]) > m_stopValue) {
								isFinish = false;
							}
						}
						if (isFinish) {
							// Main loop exit condition
							return m_sourcePoint;
						}
						else {
							firstCurrentPoint = currentPoint;
							continue;
						}
					}
					// Loop exit condition
					else {
						break;
					}
				}
			}
			else {
				firstCurrentPoint = currentPoint;
				continue;
			}
		}

		Number modulus = modulusList(diffListList(currentPoint, m_sourcePoint));
		if (modulus <= m_stopValue) {
			// Main loop exit condition
			return currentPoint;
		}
		else {
			getNewDirections(getStepLengths(currentPoint, m_sourcePoint));
			m_steps = sourceSteps;
			m_sourcePoint = currentPoint;
			firstCurrentPoint = currentPoint;
		}
	}
}

void Rosenbrock::getNewDirections(QList<Number> stepSizes)
{
	QList<QList<Number> > gramStepOne;
	for (int i = 0; i < stepSizes.size(); i++) {
		if (stepSizes[i] == 0) {
			gramStepOne << m_directions[i];
		}
		else {
			QList<Number> element;
			for (int j = i; j < stepSizes.size(); j++) {
				if (element != QList<Number>()) {
					element = sumListList(element, productListNumber(m_directions[j], stepSizes[j]));
				}
				else {
					element = productListNumber(m_directions[j], stepSizes[j]);
				}
			}
			gramStepOne << element;
		}
	}

	QList<QList<Number> > gramStepTwo;
	for (int i = 0; i < stepSizes.size(); i++) {
		QList<Number> element;

		if (i == 0) {
			element = gramStepOne[i];
		}
		else {
			QList<Number> subtractin;
			for (int j = 0; j < i; j++) {
				subtractin = productListNumber(gramStepTwo[j], productListList(gramStepOne[i], gramStepTwo[j]));
				if (j != 0) {
					subtractin = sumListList(subtractin, gramStepTwo[j]);
				}
			}

			element = diffListList(gramStepOne[i], subtractin);
		}

		m_directions[i] = quotientListNumber(element, modulusList(element));
		gramStepTwo << m_directions[i];
	}
}

QList<Number> Rosenbrock::getStepLengths(QList<Number> currentPoint, QList<Number> previousPoint)
{
	QList<QList<Number> > equationCoefficients;
	equationCoefficients << diffListList(currentPoint, previousPoint);
	foreach (QList<Number> direction, m_directions) {
		equationCoefficients << direction;
	}

	return solveEquationSystem(equationCoefficients);
}

// First list of coefficients is equations results
QList<Number> Rosenbrock::solveEquationSystem(QList<QList<Number> > coefficients)
{
	QList<Number> result;

	QVector<QVector<Number> > mainMatrix;
	for (int i = 1; i < coefficients.size(); i++) {
		mainMatrix << QVector<Number>::fromList(coefficients[i]);
	}
	Number mainDeterminant = countDeterminant(mainMatrix);

	for (int i = 1; i < coefficients.size(); i++) {
		QVector<QVector<Number> > elementMatrix;
		for (int j = 1; j < coefficients.size(); j++) {
			if (j == i) {
				elementMatrix << QVector<Number>::fromList(coefficients[0]);
			}
			else {
				elementMatrix << QVector<Number>::fromList(coefficients[j]);
			}
		}

		result << countDeterminant(elementMatrix) / mainDeterminant;
	}

	return result;
}

Number Rosenbrock::countDeterminant(QVector<QVector<Number> > matrix)
{
	Number result = 0;

	if (matrix.size() == 1) {
		result = matrix[0][0];
	}
	else if (matrix.size() == 2) {
		result = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
	}
	else {
		// Go threw first line
		for (int i = 0; i < matrix.size(); i++) {
			// Initialize minor matrix
			QVector<QVector<Number> > minorMatrix;
			minorMatrix.resize(matrix.size() - 1);
			for (int j = 0; j < minorMatrix.size(); j++) {
				minorMatrix[j].resize(matrix.size() - 1);
			}

			// Fill minor matrix
			for (int j = 0; j < matrix.size(); j++) {
				int k = 0;
				for (int l = 0; l < matrix.size(); l++) {
					// Don't conpy the minor column
					if (l != i) {
						minorMatrix[j - 1][k] = minorMatrix[j][l];
						k++;
					}
				}
			}

			result +=
				qPow(-1, 1 + i + 1) *
				minorMatrix[0][i] *
				countDeterminant(minorMatrix);
		}
	}

	return result;
}

QList<Number> Rosenbrock::increaseDirection(QList<Number> point, int direction)
{
	QList<Number> result = point;

	for (int i = 0; i < point.size(); i++) {
		result[i] += m_directions[direction][i] * m_steps[direction];
	}

	return result;
}

QList<Number> Rosenbrock::productListNumber(QList<Number> list, Number number)
{
	QList<Number> result;

	foreach (Number element, list) {
		result << element * number;
	}

	return result;
}

QList<Number> Rosenbrock::diffListList(QList<Number> source, QList<Number> subtractin)
{
	QList<Number> result;

	for (int i = 0; i < source.size(); i++) {
		result << source[i] - subtractin[i];
	}

	return result;
}

QList<Number> Rosenbrock::sumListList(QList<Number> source, QList<Number> item)
{
	QList<Number> result;

	for (int i = 0; i < source.size(); i++) {
		result << source[i] + item[i];
	}

	return result;
}

Number Rosenbrock::productListList(QList<Number> source, QList<Number> item)
{
	Number result = 0;

	for (int i = 0; i < source.size(); i++) {
		result += source[i] * item[i];
	}

	return result;
}

Number Rosenbrock::modulusList(QList<Number> list)
{
	Number result = 0;

	foreach (Number element, list) {
		result += qPow(element, 2);
	}

	return qSqrt(result);
}

QList<Number> Rosenbrock::quotientListNumber(QList<Number> source, Number divisor)
{
	QList<Number> result;

	foreach (Number element, source) {
		result << element / divisor;
	}

	return result;
}

Number Rosenbrock::countFunction(QList<Number> arguments)
{
	QList<RpnOperand> functionArguments;

	foreach (Number argument, arguments) {
		RpnOperand functionArgument(RpnOperandNumber, argument);
		functionArguments << functionArgument;
	}

	RpnOperand result = m_calculator->calculate(m_functionName, functionArguments);
	return result.value.value<Number>();
}
<commit_msg>Fix for crash on double using Rosenbrock method<commit_after>#include "rosenbrock.h"

#include <qmath.h>

namespace
{
	Rosenbrock instance;
}

RpnOperand Rosenbrock::calculate(FunctionCalculator *calculator, QList<RpnOperand> actualArguments)
{
	m_calculator = calculator;

	m_functionName = actualArguments[0].value.value<QString>();

	m_sourcePoint = actualArguments[1].value.value<QList<Number> >();
	if (m_calculator->functionArguments(m_functionName).size() != m_sourcePoint.size()) {
		THROW(EWrongParametersCount(QObject::tr("Source point"), m_calculator->functionArguments(m_functionName).size()));
	}

	m_stopValue = actualArguments[2].value.value<Number>();
	m_accelerationStep = actualArguments[3].value.value<Number>();
	m_decreaseStep = actualArguments[4].value.value<Number>();

	m_steps = actualArguments[5].value.value<QList<Number> >();
	if (m_calculator->functionArguments(m_functionName).size() != m_steps.size()) {
		THROW(EWrongParametersCount(QObject::tr("Coordinate steps"), m_calculator->functionArguments(m_functionName).size()));
	}

	m_wrongStepsNumber = actualArguments[6].value.value<Number>();

	// Set start directions
	m_directions.clear();
	for (int i = 0; i < m_sourcePoint.size(); i++) {
		m_directions << QList<Number>();
		for (int k = 0; k < m_sourcePoint.size(); k++) {
			if (k == i) {
				m_directions[i] << 1;
			}
			else {
				m_directions[i] << 0;
			}
		}
	}

	RpnOperand result;
	result.type = RpnOperandVector;
	result.value = QVariant::fromValue(findMinimum());
	return result;
}

QList<RpnArgument> Rosenbrock::requiredArguments()
{
	QList<RpnArgument> arguments;
	arguments
		// NOTE: QVariant() shows that number of arguments is not fixed, maybe there is other way
		<< RpnArgument(RpnOperandFunctionName, QString(), QVariant())
		<< RpnArgument(RpnOperandVector)
		<< RpnArgument(RpnOperandNumber)
		<< RpnArgument(RpnOperandNumber)
		<< RpnArgument(RpnOperandNumber)
		<< RpnArgument(RpnOperandVector)
		<< RpnArgument(RpnOperandNumber);

	return arguments;
}

QList<Number> Rosenbrock::findMinimum()
{
	QList<Number> firstCurrentPoint = m_sourcePoint;
	QList<Number> sourceSteps = m_steps;
	QList<Number> currentPoint = firstCurrentPoint;

	forever {
		forever {
			int failStepsCount = 0;
			for (int i = 0; i < currentPoint.size(); i++) {
				if (countFunction(increaseDirection(currentPoint, i)) < countFunction(currentPoint)) {
					currentPoint = increaseDirection(currentPoint, i);
					m_steps[i] = m_steps[i] * m_accelerationStep;
				}
				else {
					m_steps[i] = m_steps[i] * m_decreaseStep;
					failStepsCount++;
				}
			}

			if (countFunction(currentPoint) == countFunction(firstCurrentPoint)) {
				if (countFunction(currentPoint) < countFunction(m_sourcePoint)) {
					// Loop exit condition
					break;
				}
				else if (countFunction(currentPoint) == countFunction(m_sourcePoint)) {
					if (failStepsCount <= m_wrongStepsNumber) {
						bool isFinish = true;
						for (int i = 0; i < m_steps.size(); i++) {
							if (qAbs(m_steps[i]) > m_stopValue) {
								isFinish = false;
							}
						}
						if (isFinish) {
							// Main loop exit condition
							return m_sourcePoint;
						}
						else {
							firstCurrentPoint = currentPoint;
							continue;
						}
					}
					// Loop exit condition
					else {
						break;
					}
				}
			}
			else {
				firstCurrentPoint = currentPoint;
				continue;
			}
		}

		Number modulus = modulusList(diffListList(currentPoint, m_sourcePoint));
		if (modulus <= m_stopValue) {
			// Main loop exit condition
			return currentPoint;
		}
		else {
			getNewDirections(getStepLengths(currentPoint, m_sourcePoint));
			m_steps = sourceSteps;
			m_sourcePoint = currentPoint;
			firstCurrentPoint = currentPoint;
		}
	}
}

void Rosenbrock::getNewDirections(QList<Number> stepSizes)
{
	QList<QList<Number> > gramStepOne;
	for (int i = 0; i < stepSizes.size(); i++) {
		if (stepSizes[i] == 0) {
			gramStepOne << m_directions[i];
		}
		else {
			QList<Number> element;
			for (int j = i; j < stepSizes.size(); j++) {
				if (element != QList<Number>()) {
					element = sumListList(element, productListNumber(m_directions[j], stepSizes[j]));
				}
				else {
					element = productListNumber(m_directions[j], stepSizes[j]);
				}
			}
			gramStepOne << element;
		}
	}

	QList<QList<Number> > gramStepTwo;
	for (int i = 0; i < stepSizes.size(); i++) {
		QList<Number> element;

		if (i == 0) {
			element = gramStepOne[i];
		}
		else {
			QList<Number> subtractin;
			for (int j = 0; j < i; j++) {
				subtractin = productListNumber(gramStepTwo[j], productListList(gramStepOne[i], gramStepTwo[j]));
				if (j != 0) {
					subtractin = sumListList(subtractin, gramStepTwo[j]);
				}
			}

			element = diffListList(gramStepOne[i], subtractin);
		}

		m_directions[i] = quotientListNumber(element, modulusList(element));
		gramStepTwo << m_directions[i];
	}
}

QList<Number> Rosenbrock::getStepLengths(QList<Number> currentPoint, QList<Number> previousPoint)
{
	QList<QList<Number> > equationCoefficients;
	equationCoefficients << diffListList(currentPoint, previousPoint);
	foreach (QList<Number> direction, m_directions) {
		equationCoefficients << direction;
	}

	return solveEquationSystem(equationCoefficients);
}

// First list of coefficients is equations results
QList<Number> Rosenbrock::solveEquationSystem(QList<QList<Number> > coefficients)
{
	QList<Number> result;

	QVector<QVector<Number> > mainMatrix;
	for (int i = 1; i < coefficients.size(); i++) {
		mainMatrix << QVector<Number>::fromList(coefficients[i]);
	}
	Number mainDeterminant = countDeterminant(mainMatrix);

	for (int i = 1; i < coefficients.size(); i++) {
		QVector<QVector<Number> > elementMatrix;
		for (int j = 1; j < coefficients.size(); j++) {
			if (j == i) {
				elementMatrix << QVector<Number>::fromList(coefficients[0]);
			}
			else {
				elementMatrix << QVector<Number>::fromList(coefficients[j]);
			}
		}

		result << countDeterminant(elementMatrix) / mainDeterminant;
	}

	return result;
}

Number Rosenbrock::countDeterminant(QVector<QVector<Number> > matrix)
{
	Number result = 0;

	if (matrix.size() == 1) {
		result = matrix[0][0];
	}
	else if (matrix.size() == 2) {
		result = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
	}
	else {
		// Go threw first line
		for (int i = 0; i < matrix.size(); i++) {
			// Initialize minor matrix
			QVector<QVector<Number> > minorMatrix;
			minorMatrix.resize(matrix.size() - 1);
			for (int j = 0; j < minorMatrix.size(); j++) {
				minorMatrix[j].resize(matrix.size() - 1);
			}

			// Fill minor matrix
			for (int j = 0; j < matrix.size(); j++) {
				int k = 0;
				for (int l = 0; l < matrix.size(); l++) {
					// Don't conpy the minor column
					if (l != i) {
						minorMatrix[j - 1][k] = minorMatrix[j][l];
						k++;
					}
				}
			}

			result +=
				qPow(-1, 1 + i + 1) *
				minorMatrix[0][i] *
				countDeterminant(minorMatrix);
		}
	}

	return result;
}

QList<Number> Rosenbrock::increaseDirection(QList<Number> point, int direction)
{
	QList<Number> result = point;

	for (int i = 0; i < point.size(); i++) {
		result[i] += m_directions[direction][i] * m_steps[direction];
	}

	return result;
}

QList<Number> Rosenbrock::productListNumber(QList<Number> list, Number number)
{
	QList<Number> result;

	foreach (Number element, list) {
		result << element * number;
	}

	return result;
}

QList<Number> Rosenbrock::diffListList(QList<Number> source, QList<Number> subtractin)
{
	QList<Number> result;

	for (int i = 0; i < source.size(); i++) {
		result << source[i] - subtractin[i];
	}

	return result;
}

QList<Number> Rosenbrock::sumListList(QList<Number> source, QList<Number> item)
{
	QList<Number> result;

	for (int i = 0; i < source.size(); i++) {
		result << source[i] + item[i];
	}

	return result;
}

Number Rosenbrock::productListList(QList<Number> source, QList<Number> item)
{
	Number result = 0;

	for (int i = 0; i < source.size(); i++) {
		result += source[i] * item[i];
	}

	return result;
}

Number Rosenbrock::modulusList(QList<Number> list)
{
	Number result = 0;

	foreach (Number element, list) {
		result += qPow(element, 2);
	}

	return qSqrt(result);
}

QList<Number> Rosenbrock::quotientListNumber(QList<Number> source, Number divisor)
{
	QList<Number> result;

	foreach (Number element, source) {
		result << element / divisor;
	}

	return result;
}

Number Rosenbrock::countFunction(QList<Number> arguments)
{
	QList<RpnOperand> functionArguments;

	foreach (Number argument, arguments) {
		RpnOperand functionArgument(RpnOperandNumber, argument);
		functionArguments << functionArgument;
	}

	RpnOperand result = m_calculator->calculate(m_functionName, functionArguments);
	return result.value.value<Number>();
}
<|endoftext|>


<commit_before>/* mbed Microcontroller Library
 * Copyright (c) 2018 ARM Limited
 *
 * 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 "hal/LowPowerTickerWrapper.h"
#include "platform/Callback.h"

LowPowerTickerWrapper::LowPowerTickerWrapper(const ticker_data_t *data, const ticker_interface_t *interface, uint32_t min_cycles_between_writes, uint32_t min_cycles_until_match)
    : _intf(data->interface), _min_count_between_writes(min_cycles_between_writes + 1), _min_count_until_match(min_cycles_until_match + 1), _suspended(false)
{
    core_util_critical_section_enter();

    this->data.interface = interface;
    this->data.queue = data->queue;
    _reset();

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::irq_handler(ticker_irq_handler_type handler)
{
    core_util_critical_section_enter();

    if (_suspended) {
        if (handler) {
            handler(&data);
        }
        core_util_critical_section_exit();
        return;
    }

    if (_pending_fire_now || _match_check(_intf->read())) {
        _timeout.detach();
        _pending_timeout = false;
        _pending_match = false;
        _pending_fire_now = false;
        if (handler) {
            handler(&data);
        }
    } else {
        // Spurious interrupt
        _intf->clear_interrupt();
    }

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::suspend()
{
    core_util_critical_section_enter();

    // Wait until rescheduling is allowed
    while (!_set_interrupt_allowed) {
        timestamp_t current = _intf->read();
        if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) {
            _set_interrupt_allowed  = true;
        }
    }

    _reset();
    _suspended = true;

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::resume()
{
    core_util_critical_section_enter();

    _suspended = false;

    core_util_critical_section_exit();
}

bool LowPowerTickerWrapper::timeout_pending()
{
    core_util_critical_section_enter();

    bool pending = _pending_timeout;

    core_util_critical_section_exit();
    return pending;
}

void LowPowerTickerWrapper::init()
{
    core_util_critical_section_enter();

    _reset();
    _intf->init();

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::free()
{
    core_util_critical_section_enter();

    _reset();
    _intf->free();

    core_util_critical_section_exit();
}

uint32_t LowPowerTickerWrapper::read()
{
    core_util_critical_section_enter();

    timestamp_t current = _intf->read();
    if (_match_check(current)) {
        _intf->fire_interrupt();
    }

    core_util_critical_section_exit();
    return current;
}

void LowPowerTickerWrapper::set_interrupt(timestamp_t timestamp)
{
    core_util_critical_section_enter();

    _last_set_interrupt = _intf->read();
    _cur_match_time = timestamp;
    _pending_match = true;
    _schedule_match(_last_set_interrupt);

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::disable_interrupt()
{
    core_util_critical_section_enter();

    _intf->disable_interrupt();

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::clear_interrupt()
{
    core_util_critical_section_enter();

    _intf->clear_interrupt();

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::fire_interrupt()
{
    core_util_critical_section_enter();

    _pending_fire_now = 1;
    _intf->fire_interrupt();

    core_util_critical_section_exit();
}

const ticker_info_t *LowPowerTickerWrapper::get_info()
{

    core_util_critical_section_enter();

    const ticker_info_t *info = _intf->get_info();

    core_util_critical_section_exit();
    return info;
}

void LowPowerTickerWrapper::_reset()
{
    MBED_ASSERT(core_util_in_critical_section());

    _timeout.detach();
    _pending_timeout = false;
    _pending_match = false;
    _pending_fire_now = false;
    _set_interrupt_allowed = true;
    _cur_match_time = 0;
    _last_set_interrupt = 0;
    _last_actual_set_interrupt = 0;

    const ticker_info_t *info = _intf->get_info();
    if (info->bits >= 32) {
        _mask = 0xffffffff;
    } else {
        _mask = ((uint64_t)1 << info->bits) - 1;
    }

    // Round us_per_tick up
    _us_per_tick = (1000000 + info->frequency - 1) / info->frequency;
}

void LowPowerTickerWrapper::_timeout_handler()
{
    core_util_critical_section_enter();
    _pending_timeout = false;

    timestamp_t current = _intf->read();
    if (_ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time)) {
        _intf->fire_interrupt();
    } else {
        _schedule_match(current);
    }

    core_util_critical_section_exit();
}

bool LowPowerTickerWrapper::_match_check(timestamp_t current)
{
    MBED_ASSERT(core_util_in_critical_section());

    if (!_pending_match) {
        return false;
    }
    return _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time);
}

uint32_t LowPowerTickerWrapper::_lp_ticks_to_us(uint32_t ticks)
{
    MBED_ASSERT(core_util_in_critical_section());

    // Add 4 microseconds to round up the micro second ticker time (which has a frequency of at least 250KHz - 4us period)
    return _us_per_tick * ticks + 4;
}

void LowPowerTickerWrapper::_schedule_match(timestamp_t current)
{
    MBED_ASSERT(core_util_in_critical_section());

    // Check if _intf->set_interrupt is allowed
    if (!_set_interrupt_allowed) {
        if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) {
            _set_interrupt_allowed  = true;
        }
    }

    uint32_t cycles_until_match = (_cur_match_time - _last_set_interrupt) & _mask;
    bool too_close = cycles_until_match < _min_count_until_match;

    if (!_set_interrupt_allowed) {

        // Can't use _intf->set_interrupt so use microsecond Timeout instead
        uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match;
        _timeout.attach_us(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks));
        _pending_timeout = true;
        return;
    }

    if (!too_close) {

        // Schedule LP ticker
        _intf->set_interrupt(_cur_match_time);
        current = _intf->read();
        _last_actual_set_interrupt = current;
        _set_interrupt_allowed  = false;

        // Check for overflow
        uint32_t new_cycles_until_match = (_cur_match_time - current) & _mask;
        if (new_cycles_until_match > cycles_until_match) {
            // Overflow so fire now
            _intf->fire_interrupt();
            return;
        }

        // Update variables with new time
        cycles_until_match = new_cycles_until_match;
        too_close = cycles_until_match < _min_count_until_match;
    }

    if (too_close) {

        // Low power ticker incremented to less than _min_count_until_match
        // so low power ticker may not fire. Use Timeout to ensure it does fire.
        uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match;
        _timeout.attach_us(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks));
        _pending_timeout = true;
        return;
    }
}
<commit_msg>Speed optimization for LowPowerTickerWrapper<commit_after>/* mbed Microcontroller Library
 * Copyright (c) 2018 ARM Limited
 *
 * 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 "hal/LowPowerTickerWrapper.h"
#include "platform/Callback.h"

LowPowerTickerWrapper::LowPowerTickerWrapper(const ticker_data_t *data, const ticker_interface_t *interface, uint32_t min_cycles_between_writes, uint32_t min_cycles_until_match)
    : _intf(data->interface), _min_count_between_writes(min_cycles_between_writes + 1), _min_count_until_match(min_cycles_until_match + 1), _suspended(false)
{
    core_util_critical_section_enter();

    this->data.interface = interface;
    this->data.queue = data->queue;
    _reset();

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::irq_handler(ticker_irq_handler_type handler)
{
    core_util_critical_section_enter();

    if (_suspended) {
        if (handler) {
            handler(&data);
        }
        core_util_critical_section_exit();
        return;
    }

    if (_pending_fire_now || _match_check(_intf->read())) {
        _timeout.detach();
        _pending_timeout = false;
        _pending_match = false;
        _pending_fire_now = false;
        if (handler) {
            handler(&data);
        }
    } else {
        // Spurious interrupt
        _intf->clear_interrupt();
    }

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::suspend()
{
    core_util_critical_section_enter();

    // Wait until rescheduling is allowed
    while (!_set_interrupt_allowed) {
        timestamp_t current = _intf->read();
        if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) {
            _set_interrupt_allowed  = true;
        }
    }

    _reset();
    _suspended = true;

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::resume()
{
    core_util_critical_section_enter();

    _suspended = false;

    core_util_critical_section_exit();
}

bool LowPowerTickerWrapper::timeout_pending()
{
    core_util_critical_section_enter();

    bool pending = _pending_timeout;

    core_util_critical_section_exit();
    return pending;
}

void LowPowerTickerWrapper::init()
{
    core_util_critical_section_enter();

    _reset();
    _intf->init();

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::free()
{
    core_util_critical_section_enter();

    _reset();
    _intf->free();

    core_util_critical_section_exit();
}

uint32_t LowPowerTickerWrapper::read()
{
    core_util_critical_section_enter();

    timestamp_t current = _intf->read();
    if (_match_check(current)) {
        _intf->fire_interrupt();
    }

    core_util_critical_section_exit();
    return current;
}

void LowPowerTickerWrapper::set_interrupt(timestamp_t timestamp)
{
    core_util_critical_section_enter();

    _last_set_interrupt = _intf->read();
    _cur_match_time = timestamp;
    _pending_match = true;
    _schedule_match(_last_set_interrupt);

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::disable_interrupt()
{
    core_util_critical_section_enter();

    _intf->disable_interrupt();

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::clear_interrupt()
{
    core_util_critical_section_enter();

    _intf->clear_interrupt();

    core_util_critical_section_exit();
}

void LowPowerTickerWrapper::fire_interrupt()
{
    core_util_critical_section_enter();

    _pending_fire_now = 1;
    _intf->fire_interrupt();

    core_util_critical_section_exit();
}

const ticker_info_t *LowPowerTickerWrapper::get_info()
{

    core_util_critical_section_enter();

    const ticker_info_t *info = _intf->get_info();

    core_util_critical_section_exit();
    return info;
}

void LowPowerTickerWrapper::_reset()
{
    MBED_ASSERT(core_util_in_critical_section());

    _timeout.detach();
    _pending_timeout = false;
    _pending_match = false;
    _pending_fire_now = false;
    _set_interrupt_allowed = true;
    _cur_match_time = 0;
    _last_set_interrupt = 0;
    _last_actual_set_interrupt = 0;

    const ticker_info_t *info = _intf->get_info();
    if (info->bits >= 32) {
        _mask = 0xffffffff;
    } else {
        _mask = ((uint64_t)1 << info->bits) - 1;
    }

    // Round us_per_tick up
    _us_per_tick = (1000000 + info->frequency - 1) / info->frequency;
}

void LowPowerTickerWrapper::_timeout_handler()
{
    core_util_critical_section_enter();
    _pending_timeout = false;

    timestamp_t current = _intf->read();
    if (_ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time)) {
        _intf->fire_interrupt();
    } else {
        _schedule_match(current);
    }

    core_util_critical_section_exit();
}

bool LowPowerTickerWrapper::_match_check(timestamp_t current)
{
    MBED_ASSERT(core_util_in_critical_section());

    if (!_pending_match) {
        return false;
    }
    return _ticker_match_interval_passed(_last_set_interrupt, current, _cur_match_time);
}

uint32_t LowPowerTickerWrapper::_lp_ticks_to_us(uint32_t ticks)
{
    MBED_ASSERT(core_util_in_critical_section());

    // Add 4 microseconds to round up the micro second ticker time (which has a frequency of at least 250KHz - 4us period)
    return _us_per_tick * ticks + 4;
}

void LowPowerTickerWrapper::_schedule_match(timestamp_t current)
{
    MBED_ASSERT(core_util_in_critical_section());

    // Check if _intf->set_interrupt is allowed
    if (!_set_interrupt_allowed) {
        if (((current - _last_actual_set_interrupt) & _mask) >= _min_count_between_writes) {
            _set_interrupt_allowed  = true;
        }
    }

    uint32_t cycles_until_match = (_cur_match_time - _last_set_interrupt) & _mask;
    bool too_close = cycles_until_match < _min_count_until_match;

    if (!_set_interrupt_allowed) {

        // Can't use _intf->set_interrupt so use microsecond Timeout instead

        // Speed optimization - if a timer has already been scheduled
        // then don't schedule it again.
        if (!_pending_timeout) {
            uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match;
            _timeout.attach_us(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks));
            _pending_timeout = true;
        }
        return;
    }

    if (!too_close) {

        // Schedule LP ticker
        _intf->set_interrupt(_cur_match_time);
        current = _intf->read();
        _last_actual_set_interrupt = current;
        _set_interrupt_allowed  = false;

        // Check for overflow
        uint32_t new_cycles_until_match = (_cur_match_time - current) & _mask;
        if (new_cycles_until_match > cycles_until_match) {
            // Overflow so fire now
            _intf->fire_interrupt();
            return;
        }

        // Update variables with new time
        cycles_until_match = new_cycles_until_match;
        too_close = cycles_until_match < _min_count_until_match;
    }

    if (too_close) {

        // Low power ticker incremented to less than _min_count_until_match
        // so low power ticker may not fire. Use Timeout to ensure it does fire.
        uint32_t ticks = cycles_until_match < _min_count_until_match ? cycles_until_match : _min_count_until_match;
        _timeout.attach_us(mbed::callback(this, &LowPowerTickerWrapper::_timeout_handler), _lp_ticks_to_us(ticks));
        _pending_timeout = true;
        return;
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010 Manjeet Dahiya
 *
 * Author:
 *	Manjeet Dahiya
 *
 * Source:
 *	http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * 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.
 *
 */

#include "QXmppRoster.h"
#include "QXmppUtils.h"
#include "QXmppRosterIq.h"
#include "QXmppPresence.h"
#include "QXmppStream.h"

QXmppRoster::QXmppRoster(QXmppStream* stream) : m_stream(stream),
                                m_isRosterReceived(false)
{
}

QXmppRoster::~QXmppRoster()
{

}

void QXmppRoster::disconnected()
{
    m_entries = QMap<QString, QXmppRoster::QXmppRosterEntry>();
    m_presences = QMap<QString, QMap<QString, QXmppPresence> >();
    m_isRosterReceived = false;
}

void QXmppRoster::presenceReceived(const QXmppPresence& presence)
{
    QString jid = presence.from();
    QString bareJid = jidToBareJid(jid);
    QString resource = jidToResource(jid);

    if (presence.getType() == QXmppPresence::Available)
        m_presences[bareJid][resource] = presence;
    else if (presence.getType() == QXmppPresence::Unavailable)
        m_presences[bareJid].remove(resource);
    else
        return;

    emit presenceChanged(bareJid, resource);
}

void QXmppRoster::rosterIqReceived(const QXmppRosterIq& rosterIq)
{
    switch(rosterIq.type())
    {
    case QXmppIq::Set:
    case QXmppIq::Result:
        {
            QList<QXmppRosterIq::Item> items = rosterIq.items();
            for(int i = 0; i < items.count(); ++i)
            {
                QString bareJid = items.at(i).bareJid();
                m_entries[bareJid].setBareJid(bareJid);
                m_entries[bareJid].setName(items.at(i).name());
                m_entries[bareJid].setSubscriptionType(
                    static_cast<QXmppRosterEntry::SubscriptionType>(
                            items.at(i).subscriptionType()));
                m_entries[bareJid].setSubscriptionStatus(
                        items.at(i).subscriptionStatus());
                m_entries[bareJid].setGroups(items.at(i).groups());
                emit rosterChanged(bareJid);
            }
            if(rosterIq.type() == QXmppIq::Set) // send result iq
            {
                QXmppIq returnIq(QXmppIq::Result);
                returnIq.setId(rosterIq.id());
                m_stream->sendPacket(returnIq);
            }
            break;
        }
    default:
        break;
    }
}

void QXmppRoster::rosterRequestIqReceived(const QXmppRosterIq& rosterIq)
{
    switch(rosterIq.type())
    {
    case QXmppIq::Set:
    case QXmppIq::Result:
        {
            QList<QXmppRosterIq::Item> items = rosterIq.items();
            for(int i = 0; i < items.count(); ++i)
            {
                QString bareJid = items.at(i).bareJid();
                m_entries[bareJid].setBareJid(bareJid);
                m_entries[bareJid].setName(items.at(i).name());
                m_entries[bareJid].setSubscriptionType(
                    static_cast<QXmppRosterEntry::SubscriptionType>(
                            items.at(i).subscriptionType()));
                m_entries[bareJid].setSubscriptionStatus(
                        items.at(i).subscriptionStatus());
                m_entries[bareJid].setGroups(items.at(i).groups());
            }
            if(rosterIq.type() == QXmppIq::Set) // send result iq
            {
                QXmppIq returnIq(QXmppIq::Result);
                returnIq.setId(rosterIq.id());
                m_stream->sendPacket(returnIq);
            }
            m_isRosterReceived = true;
            emit rosterReceived();
            break;
        }
    default:
        break;
    }
}

/// Returns the bareJid of the roster entry.
///
/// \return bareJid as a QString
///

QString QXmppRoster::QXmppRosterEntry::bareJid() const
{
    return m_bareJid;
}

/// Returns the name of the roster entry.
///
/// \return name as a QString
///

QString QXmppRoster::QXmppRosterEntry::name() const
{
    return m_name;
}

/// Returns the subscription type of the roster entry.
///
/// \return QXmppRosterEntry::SubscriptionType
///

QXmppRoster::QXmppRosterEntry::SubscriptionType
        QXmppRoster::QXmppRosterEntry::subscriptionType() const
{
    return m_type;
}

/// Sets the subscription status of the roster entry. It is the "ask"
/// attribute in the Roster IQ stanza. Its value can be "subscribe" or "unsubscribe"
/// or empty.
///
/// \return subscription status as a QString
///
///

QString QXmppRoster::QXmppRosterEntry::subscriptionStatus() const
{
    return m_subscriptionStatus;
}

/// Returns the groups of the roster entry.
///
/// \return QSet<QString> list of all the groups
///

QSet<QString> QXmppRoster::QXmppRosterEntry::groups() const
{
    return m_groups;
}

/// Sets the bareJid of the roster entry.
///
/// \param bareJid as a QString
///

void QXmppRoster::QXmppRosterEntry::setBareJid(const QString& bareJid )
{
    m_bareJid = bareJid ;
}

/// Sets the name of the roster entry.
///
/// \param name as a QString
///

void QXmppRoster::QXmppRosterEntry::setName(const QString& name)
{
    m_name = name;
}

/// Sets the subscription type of the roster entry.
///
/// \param type as a QXmppRosterEntry::SubscriptionType
///

void QXmppRoster::QXmppRosterEntry::setSubscriptionType(
        QXmppRosterEntry::SubscriptionType type)
{
    m_type = type;
}

/// Sets the subscription status of the roster entry. It is the "ask"
/// attribute in the Roster IQ stanza. Its value can be "subscribe" or "unsubscribe"
/// or empty.
///
/// \param status as a QString
///

void QXmppRoster::QXmppRosterEntry::setSubscriptionStatus(const QString& status)
{
    m_subscriptionStatus = status;
}

/// Adds the group entry of the roster entry.
///
/// \param group name as a QString
///

void QXmppRoster::QXmppRosterEntry::addGroupEntry(const QString& group)
{
    m_groups << group;
}

/// Sets the groups of the roster entry.
///
/// \param groups list of all the groups as a QSet<QString>
///

void QXmppRoster::QXmppRosterEntry::setGroups(const QSet<QString>& groups)
{
    m_groups = groups;
}

/// Function to get all the bareJids present in the roster.
///
/// \return QStringList list of all the bareJids
///

QStringList QXmppRoster::getRosterBareJids() const
{
    return m_entries.keys();
}

/// Returns the roster entry of the given bareJid. If the bareJid is not in the
/// database and empty QXmppRoster::QXmppRosterEntry will be returned.
///
/// \param bareJid as a QString
/// \return QXmppRoster::QXmppRosterEntry
///

QXmppRoster::QXmppRosterEntry QXmppRoster::getRosterEntry(
        const QString& bareJid) const
{
    // will return blank entry if bareJid does'nt exist
    if(m_entries.contains(bareJid))
        return m_entries.value(bareJid);
    else
    {
        qWarning("QXmppRoster::getRosterEntry(): bareJid doesn't exist in roster db");
        return QXmppRoster::QXmppRosterEntry();
    }
}

/// [OBSOLETE] Returns all the roster entries in the database.
///
/// \return Map of bareJid and its respective QXmppRoster::QXmppRosterEntry
///
/// \note This function is obsolete, use getRosterBareJids() and
/// getRosterEntry() to get all the roster entries.
///

QMap<QString, QXmppRoster::QXmppRosterEntry>
        QXmppRoster::getRosterEntries() const
{
    return m_entries;
}

/// Get all the associated resources with the given bareJid.
///
/// \param bareJid as a QString
/// \return list of associated resources as a QStringList
///

QStringList QXmppRoster::getResources(const QString& bareJid) const
{
    if(m_presences.contains(bareJid))
    {
        return m_presences[bareJid].keys();
    }
    else
        return QStringList();
}

/// Get all the presences of all the resources of the given bareJid. A bareJid
/// can have multiple resources and each resource will have a presence
/// associated with it.
///
/// \param bareJid as a QString
/// \return Map of resource and its respective presence QMap<QString, QXmppPresence>
///

QMap<QString, QXmppPresence> QXmppRoster::getAllPresencesForBareJid(
        const QString& bareJid) const
{
    if(m_presences.contains(bareJid))
        return m_presences[bareJid];
    else
    {
        qWarning("QXmppRoster::getAllPresences(): invalid bareJid");
        return QMap<QString, QXmppPresence>();
    }
}

/// Get the presence of the given resource of the given bareJid.
///
/// \param bareJid as a QString
/// \param resource as a QString
/// \return QXmppPresence
///

QXmppPresence QXmppRoster::getPresence(const QString& bareJid,
                                       const QString& resource) const
{
    if(m_presences.contains(bareJid) && m_presences[bareJid].contains(resource))
        return m_presences[bareJid][resource];
    else
    {
        qWarning("QXmppRoster::getPresence(): invalid bareJid");
        return QXmppPresence();
    }
}

/// [OBSOLETE] Returns all the presence entries in the database.
///
/// \return Map of bareJid and map of resource and its presence that is
/// QMap<QString, QMap<QString, QXmppPresence> >
///
/// \note This function is obsolete, use getRosterBareJids(), getResources()
/// and getPresence() or getAllPresencesForBareJid()
/// to get all the presence entries.

QMap<QString, QMap<QString, QXmppPresence> > QXmppRoster::getAllPresences() const
{
    return m_presences;
}

/// Function to check whether the roster has been received or not.
///
/// \return true if roster received else false

bool QXmppRoster::isRosterReceived()
{
    return m_isRosterReceived;
}

QString QXmppRoster::QXmppRosterEntry::getBareJid() const
{
    return m_bareJid;
}

QString QXmppRoster::QXmppRosterEntry::getName() const
{
    return m_name;
}

QXmppRoster::QXmppRosterEntry::SubscriptionType
        QXmppRoster::QXmppRosterEntry::getSubscriptionType() const
{
    return m_type;
}

QString QXmppRoster::QXmppRosterEntry::getSubscriptionStatus() const
{
    return m_subscriptionStatus;
}

QSet<QString> QXmppRoster::QXmppRosterEntry::getGroups() const
{
    return m_groups;
}
<commit_msg>silence warning when QXmppRoster::getAllPresencesForBareJid is called for an unknown JID<commit_after>/*
 * Copyright (C) 2008-2010 Manjeet Dahiya
 *
 * Author:
 *	Manjeet Dahiya
 *
 * Source:
 *	http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * 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.
 *
 */

#include "QXmppRoster.h"
#include "QXmppUtils.h"
#include "QXmppRosterIq.h"
#include "QXmppPresence.h"
#include "QXmppStream.h"

QXmppRoster::QXmppRoster(QXmppStream* stream) : m_stream(stream),
                                m_isRosterReceived(false)
{
}

QXmppRoster::~QXmppRoster()
{

}

void QXmppRoster::disconnected()
{
    m_entries = QMap<QString, QXmppRoster::QXmppRosterEntry>();
    m_presences = QMap<QString, QMap<QString, QXmppPresence> >();
    m_isRosterReceived = false;
}

void QXmppRoster::presenceReceived(const QXmppPresence& presence)
{
    QString jid = presence.from();
    QString bareJid = jidToBareJid(jid);
    QString resource = jidToResource(jid);

    if (presence.getType() == QXmppPresence::Available)
        m_presences[bareJid][resource] = presence;
    else if (presence.getType() == QXmppPresence::Unavailable)
        m_presences[bareJid].remove(resource);
    else
        return;

    emit presenceChanged(bareJid, resource);
}

void QXmppRoster::rosterIqReceived(const QXmppRosterIq& rosterIq)
{
    switch(rosterIq.type())
    {
    case QXmppIq::Set:
    case QXmppIq::Result:
        {
            QList<QXmppRosterIq::Item> items = rosterIq.items();
            for(int i = 0; i < items.count(); ++i)
            {
                QString bareJid = items.at(i).bareJid();
                m_entries[bareJid].setBareJid(bareJid);
                m_entries[bareJid].setName(items.at(i).name());
                m_entries[bareJid].setSubscriptionType(
                    static_cast<QXmppRosterEntry::SubscriptionType>(
                            items.at(i).subscriptionType()));
                m_entries[bareJid].setSubscriptionStatus(
                        items.at(i).subscriptionStatus());
                m_entries[bareJid].setGroups(items.at(i).groups());
                emit rosterChanged(bareJid);
            }
            if(rosterIq.type() == QXmppIq::Set) // send result iq
            {
                QXmppIq returnIq(QXmppIq::Result);
                returnIq.setId(rosterIq.id());
                m_stream->sendPacket(returnIq);
            }
            break;
        }
    default:
        break;
    }
}

void QXmppRoster::rosterRequestIqReceived(const QXmppRosterIq& rosterIq)
{
    switch(rosterIq.type())
    {
    case QXmppIq::Set:
    case QXmppIq::Result:
        {
            QList<QXmppRosterIq::Item> items = rosterIq.items();
            for(int i = 0; i < items.count(); ++i)
            {
                QString bareJid = items.at(i).bareJid();
                m_entries[bareJid].setBareJid(bareJid);
                m_entries[bareJid].setName(items.at(i).name());
                m_entries[bareJid].setSubscriptionType(
                    static_cast<QXmppRosterEntry::SubscriptionType>(
                            items.at(i).subscriptionType()));
                m_entries[bareJid].setSubscriptionStatus(
                        items.at(i).subscriptionStatus());
                m_entries[bareJid].setGroups(items.at(i).groups());
            }
            if(rosterIq.type() == QXmppIq::Set) // send result iq
            {
                QXmppIq returnIq(QXmppIq::Result);
                returnIq.setId(rosterIq.id());
                m_stream->sendPacket(returnIq);
            }
            m_isRosterReceived = true;
            emit rosterReceived();
            break;
        }
    default:
        break;
    }
}

/// Returns the bareJid of the roster entry.
///
/// \return bareJid as a QString
///

QString QXmppRoster::QXmppRosterEntry::bareJid() const
{
    return m_bareJid;
}

/// Returns the name of the roster entry.
///
/// \return name as a QString
///

QString QXmppRoster::QXmppRosterEntry::name() const
{
    return m_name;
}

/// Returns the subscription type of the roster entry.
///
/// \return QXmppRosterEntry::SubscriptionType
///

QXmppRoster::QXmppRosterEntry::SubscriptionType
        QXmppRoster::QXmppRosterEntry::subscriptionType() const
{
    return m_type;
}

/// Sets the subscription status of the roster entry. It is the "ask"
/// attribute in the Roster IQ stanza. Its value can be "subscribe" or "unsubscribe"
/// or empty.
///
/// \return subscription status as a QString
///
///

QString QXmppRoster::QXmppRosterEntry::subscriptionStatus() const
{
    return m_subscriptionStatus;
}

/// Returns the groups of the roster entry.
///
/// \return QSet<QString> list of all the groups
///

QSet<QString> QXmppRoster::QXmppRosterEntry::groups() const
{
    return m_groups;
}

/// Sets the bareJid of the roster entry.
///
/// \param bareJid as a QString
///

void QXmppRoster::QXmppRosterEntry::setBareJid(const QString& bareJid )
{
    m_bareJid = bareJid ;
}

/// Sets the name of the roster entry.
///
/// \param name as a QString
///

void QXmppRoster::QXmppRosterEntry::setName(const QString& name)
{
    m_name = name;
}

/// Sets the subscription type of the roster entry.
///
/// \param type as a QXmppRosterEntry::SubscriptionType
///

void QXmppRoster::QXmppRosterEntry::setSubscriptionType(
        QXmppRosterEntry::SubscriptionType type)
{
    m_type = type;
}

/// Sets the subscription status of the roster entry. It is the "ask"
/// attribute in the Roster IQ stanza. Its value can be "subscribe" or "unsubscribe"
/// or empty.
///
/// \param status as a QString
///

void QXmppRoster::QXmppRosterEntry::setSubscriptionStatus(const QString& status)
{
    m_subscriptionStatus = status;
}

/// Adds the group entry of the roster entry.
///
/// \param group name as a QString
///

void QXmppRoster::QXmppRosterEntry::addGroupEntry(const QString& group)
{
    m_groups << group;
}

/// Sets the groups of the roster entry.
///
/// \param groups list of all the groups as a QSet<QString>
///

void QXmppRoster::QXmppRosterEntry::setGroups(const QSet<QString>& groups)
{
    m_groups = groups;
}

/// Function to get all the bareJids present in the roster.
///
/// \return QStringList list of all the bareJids
///

QStringList QXmppRoster::getRosterBareJids() const
{
    return m_entries.keys();
}

/// Returns the roster entry of the given bareJid. If the bareJid is not in the
/// database and empty QXmppRoster::QXmppRosterEntry will be returned.
///
/// \param bareJid as a QString
/// \return QXmppRoster::QXmppRosterEntry
///

QXmppRoster::QXmppRosterEntry QXmppRoster::getRosterEntry(
        const QString& bareJid) const
{
    // will return blank entry if bareJid does'nt exist
    if(m_entries.contains(bareJid))
        return m_entries.value(bareJid);
    else
    {
        qWarning("QXmppRoster::getRosterEntry(): bareJid doesn't exist in roster db");
        return QXmppRoster::QXmppRosterEntry();
    }
}

/// [OBSOLETE] Returns all the roster entries in the database.
///
/// \return Map of bareJid and its respective QXmppRoster::QXmppRosterEntry
///
/// \note This function is obsolete, use getRosterBareJids() and
/// getRosterEntry() to get all the roster entries.
///

QMap<QString, QXmppRoster::QXmppRosterEntry>
        QXmppRoster::getRosterEntries() const
{
    return m_entries;
}

/// Get all the associated resources with the given bareJid.
///
/// \param bareJid as a QString
/// \return list of associated resources as a QStringList
///

QStringList QXmppRoster::getResources(const QString& bareJid) const
{
    if(m_presences.contains(bareJid))
        return m_presences[bareJid].keys();
    else
        return QStringList();
}

/// Get all the presences of all the resources of the given bareJid. A bareJid
/// can have multiple resources and each resource will have a presence
/// associated with it.
///
/// \param bareJid as a QString
/// \return Map of resource and its respective presence QMap<QString, QXmppPresence>
///

QMap<QString, QXmppPresence> QXmppRoster::getAllPresencesForBareJid(
        const QString& bareJid) const
{
    if(m_presences.contains(bareJid))
        return m_presences[bareJid];
    else
        return QMap<QString, QXmppPresence>();
}

/// Get the presence of the given resource of the given bareJid.
///
/// \param bareJid as a QString
/// \param resource as a QString
/// \return QXmppPresence
///

QXmppPresence QXmppRoster::getPresence(const QString& bareJid,
                                       const QString& resource) const
{
    if(m_presences.contains(bareJid) && m_presences[bareJid].contains(resource))
        return m_presences[bareJid][resource];
    else
    {
        qWarning("QXmppRoster::getPresence(): invalid bareJid");
        return QXmppPresence();
    }
}

/// [OBSOLETE] Returns all the presence entries in the database.
///
/// \return Map of bareJid and map of resource and its presence that is
/// QMap<QString, QMap<QString, QXmppPresence> >
///
/// \note This function is obsolete, use getRosterBareJids(), getResources()
/// and getPresence() or getAllPresencesForBareJid()
/// to get all the presence entries.

QMap<QString, QMap<QString, QXmppPresence> > QXmppRoster::getAllPresences() const
{
    return m_presences;
}

/// Function to check whether the roster has been received or not.
///
/// \return true if roster received else false

bool QXmppRoster::isRosterReceived()
{
    return m_isRosterReceived;
}

QString QXmppRoster::QXmppRosterEntry::getBareJid() const
{
    return m_bareJid;
}

QString QXmppRoster::QXmppRosterEntry::getName() const
{
    return m_name;
}

QXmppRoster::QXmppRosterEntry::SubscriptionType
        QXmppRoster::QXmppRosterEntry::getSubscriptionType() const
{
    return m_type;
}

QString QXmppRoster::QXmppRosterEntry::getSubscriptionStatus() const
{
    return m_subscriptionStatus;
}

QSet<QString> QXmppRoster::QXmppRosterEntry::getGroups() const
{
    return m_groups;
}
<|endoftext|>


<commit_before>#include "sdl_rw_ops.h"

using namespace Halley;

std::unique_ptr<ResourceDataReader> SDLRWOps::fromPath(const String& path, int64_t start, int64_t end)
{
	auto fp = SDL_RWFromFile(path.c_str(), "rb");
	if (!fp) {
		throw Exception("Unable to open file: " + path);
	}
	return std::make_unique<SDLRWOps>(fp, start, end, true);
}

std::unique_ptr<ResourceDataReader> SDLRWOps::fromMemory(gsl::span<const gsl::byte> span)
{
	auto fp = SDL_RWFromConstMem(span.data(), int(span.size()));
	if (!fp) {
		throw Exception("Unable to open data from memory");
	}
	return std::make_unique<SDLRWOps>(fp, 0, 0, true);
}

SDLRWOps::SDLRWOps(SDL_RWops* _fp, int64_t _start, int64_t _end, bool _closeOnFinish)
	: fp(_fp)
	, pos(_start)
	, start(_start)
	, end(_end)
	, closeOnFinish(_closeOnFinish)
{
	Expects(fp);

	if (end == -1) {
		SDL_RWseek(fp, 0, SEEK_END);
		end = SDL_RWtell(fp);
		SDL_RWseek(fp, 0, SEEK_SET);
	}

	int64_t size = end - start;
	if (size < 0) {
		throw Exception("Invalid file size for resource: " + String::integerToString(int(size)) + " bytes.");
	}
}

size_t SDLRWOps::size() const
{
	return end - start;
}

int SDLRWOps::read(gsl::span<gsl::byte> dst)
{
	if (!fp) return -1;

	size_t toRead = std::min(size_t(dst.size()), size_t(end - pos));
	SDL_RWseek(fp, pos, SEEK_SET);
	int n = static_cast<int>(SDL_RWread(fp, dst.data(), 1, static_cast<int>(toRead)));
	if (n > 0) pos += n;
	return n;
}

void SDLRWOps::close()
{
	if (fp) {
		if (closeOnFinish) {
			SDL_RWclose(fp);
		}
		fp = nullptr;
		pos = end;
	}
}

void SDLRWOps::seek(long long offset, int whence)
{
	if (whence == SEEK_SET) pos = int(offset + start);
	else if (whence == SEEK_CUR) pos += int(offset);
	else if (whence == SEEK_END) pos = int(end + offset);
	SDL_RWseek(fp, pos, SEEK_SET);
}

size_t SDLRWOps::tell() const
{
	return pos - start;
}
<commit_msg><commit_after>#include "sdl_rw_ops.h"

using namespace Halley;

std::unique_ptr<ResourceDataReader> SDLRWOps::fromPath(const String& path, int64_t start, int64_t end)
{
	auto fp = SDL_RWFromFile(path.c_str(), "rb");
	if (!fp) {
		throw Exception("Unable to open file: " + path);
	}
	return std::make_unique<SDLRWOps>(fp, start, end, true);
}

std::unique_ptr<ResourceDataReader> SDLRWOps::fromMemory(gsl::span<const gsl::byte> span)
{
	auto fp = SDL_RWFromConstMem(span.data(), int(span.size()));
	if (!fp) {
		throw Exception("Unable to open data from memory");
	}
	return std::make_unique<SDLRWOps>(fp, 0, 0, true);
}

SDLRWOps::SDLRWOps(SDL_RWops* _fp, int64_t _start, int64_t _end, bool _closeOnFinish)
	: fp(_fp)
	, pos(_start)
	, start(_start)
	, end(_end)
	, closeOnFinish(_closeOnFinish)
{
	Expects(fp);

	if (end == -1) {
		SDL_RWseek(fp, 0, SEEK_END);
		end = SDL_RWtell(fp);
		SDL_RWseek(fp, 0, SEEK_SET);
	}

	int64_t size = end - start;
	if (size < 0) {
		throw Exception("Invalid file size for resource: " + String::integerToString(int(size)) + " bytes.");
	}
}

size_t SDLRWOps::size() const
{
	return end - start;
}

int SDLRWOps::read(gsl::span<gsl::byte> dst)
{
	if (!fp) return -1;

	size_t toRead = std::min(size_t(dst.size()), size_t(end - pos));
	SDL_RWseek(fp, pos, SEEK_SET);
	int n = static_cast<int>(SDL_RWread(fp, dst.data(), 1, static_cast<int>(toRead)));
	if (n > 0) pos += n;
	return n;
}

void SDLRWOps::close()
{
	if (fp) {
		if (closeOnFinish) {
			SDL_RWclose(fp);
		}
		fp = nullptr;
		pos = end;
	}
}

void SDLRWOps::seek(int64_t offset, int whence)
{
	if (whence == SEEK_SET) pos = int(offset + start);
	else if (whence == SEEK_CUR) pos += int(offset);
	else if (whence == SEEK_END) pos = int(end + offset);
	SDL_RWseek(fp, pos, SEEK_SET);
}

size_t SDLRWOps::tell() const
{
	return pos - start;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2009 Manjeet Dahiya
 *
 * Author:
 *	Manjeet Dahiya
 *
 * Source:
 *	http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * 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.
 *
 */

#include "QXmppStanza.h"
#include "QXmppUtils.h"
#include "QXmppConstants.h"

#include <QDomElement>
#include <QXmlStreamWriter>

uint QXmppStanza::s_uniqeIdNo = 0;

QXmppStanza::Error::Error():
    m_code(0),
    m_type(static_cast<QXmppStanza::Error::Type>(-1)),
    m_condition(static_cast<QXmppStanza::Error::Condition>(-1)),
    m_text("")
{
}

QXmppStanza::Error::Error(Type type, Condition cond, const QString& text):
    m_code(0),
    m_type(type),
    m_condition(cond),
    m_text(text)
{
}

QXmppStanza::Error::Error(const QString& type, const QString& cond,
                          const QString& text):
    m_code(0),
    m_text(text)
{
    setTypeFromStr(type);
    setConditionFromStr(cond);
}

void QXmppStanza::Error::setText(const QString& text)
{
    m_text = text;
}

void QXmppStanza::Error::setCode(int code)
{
    m_code = code;
}

void QXmppStanza::Error::setCondition(QXmppStanza::Error::Condition cond)
{
    m_condition = cond;
}

void QXmppStanza::Error::setType(QXmppStanza::Error::Type type)
{
    m_type = type;
}

QString QXmppStanza::Error::getText() const
{
    return m_text;
}

int QXmppStanza::Error::getCode() const
{
    return m_code;
}

QXmppStanza::Error::Condition QXmppStanza::Error::getCondition() const
{
    return m_condition;
}

QXmppStanza::Error::Type QXmppStanza::Error::getType() const
{
    return m_type;
}

QString QXmppStanza::Error::getTypeStr() const
{
    switch(m_type)
    {
    case Cancel:
        return "cancel";
    case Continue:
        return "continue";
    case Modify:
        return "modify";
    case Auth:
        return "auth";
    case Wait:
        return "wait";
    default:
        return "";
    }
}

QString QXmppStanza::Error::getConditionStr() const
{
    switch(m_condition)
    {
    case BadRequest:
        return "bad-request";
    case Conflict:
        return "conflict";
    case FeatureNotImplemented:
        return "feature-not-implemented";
    case Forbidden:
        return "forbidden";
    case Gone:
        return "gone";
    case InternalServerError:
        return "internal-server-error";
    case ItemNotFound:
        return "item-not-found";
    case JidMalformed:
        return "jid-malformed";
    case NotAcceptable:
        return "not-acceptable";
    case NotAllowed:
        return "not-allowed";
    case NotAuthorized:
        return "not-authorized";
    case PaymentRequired:
        return "payment-required";
    case RecipientUnavailable:
        return "recipient-unavailable";
    case Redirect:
        return "redirect";
    case RegistrationRequired:
        return "registration-required";
    case RemoteServerNotFound:
        return "remote-server-not-found";
    case RemoteServerTimeout:
        return "remote-server-timeout";
    case ResourceConstraint:
        return "resource-constraint";
    case ServiceUnavailable:
        return "service-unavailable";
    case SubscriptionRequired:
        return "subscription-required";
    case UndefinedCondition:
        return "undefined-condition";
    case UnexpectedRequest:
        return "unexpected-request";
    default:
        return "";
    }
}

void QXmppStanza::Error::setTypeFromStr(const QString& type)
{
    if(type == "cancel")
        setType(Cancel);
    else if(type == "continue")
        setType(Continue);
    else if(type == "modify")
        setType(Modify);
    else if(type == "auth")
        setType(Auth);
    else if(type == "wait")
        setType(Wait);
    else
        setType(static_cast<QXmppStanza::Error::Type>(-1));
}

void QXmppStanza::Error::setConditionFromStr(const QString& type)
{
    if(type == "bad-request")
        setCondition(BadRequest);
    else if(type == "conflict")
        setCondition(Conflict);
    else if(type == "feature-not-implemented")
        setCondition(FeatureNotImplemented);
    else if(type == "forbidden")
        setCondition(Forbidden);
    else if(type == "gone")
        setCondition(Gone);
    else if(type == "internal-server-error")
        setCondition(InternalServerError);
    else if(type == "item-not-found")
        setCondition(ItemNotFound);
    else if(type == "jid-malformed")
        setCondition(JidMalformed);
    else if(type == "not-acceptable")
        setCondition(NotAcceptable);
    else if(type == "not-allowed")
        setCondition(NotAllowed);
    else if(type == "not-authorized")
        setCondition(NotAuthorized);
    else if(type == "payment-required")
        setCondition(PaymentRequired);
    else if(type == "recipient-unavailable")
        setCondition(RecipientUnavailable);
    else if(type == "redirect")
        setCondition(Redirect);
    else if(type == "registration-required")
        setCondition(RegistrationRequired);
    else if(type == "remote-server-not-found")
        setCondition(RemoteServerNotFound);
    else if(type == "remote-server-timeout")
        setCondition(RemoteServerTimeout);
    else if(type == "resource-constraint")
        setCondition(ResourceConstraint);
    else if(type == "service-unavailable")
        setCondition(ServiceUnavailable);
    else if(type == "subscription-required")
        setCondition(SubscriptionRequired);
    else if(type == "undefined-condition")
        setCondition(UndefinedCondition);
    else if(type == "unexpected-request")
        setCondition(UnexpectedRequest);
    else
        setCondition(static_cast<QXmppStanza::Error::Condition>(-1));
}

bool QXmppStanza::Error::isValid()
{
    return !(getTypeStr().isEmpty() && getConditionStr().isEmpty());
}

void QXmppStanza::Error::parse(const QDomElement &errorElement)
{
    setCode(errorElement.attribute("code").toInt());
    setTypeFromStr(errorElement.attribute("type"));

    QString text;
    QString cond;
    QDomElement element = errorElement.firstChildElement();
    while(!element.isNull())
    {
        if(element.tagName() == "text")
            text = element.text();
        else if(element.namespaceURI() == ns_stanza)
        {
            cond = element.tagName();
        }
        element = element.nextSiblingElement();
    }

    setConditionFromStr(cond);
    setText(text);
}

void QXmppStanza::Error::toXml( QXmlStreamWriter *writer ) const
{
    QString cond = getConditionStr();
    QString type = getTypeStr();

    if(cond.isEmpty() && type.isEmpty())
        return;

    writer->writeStartElement("error");
    helperToXmlAddAttribute(writer, "type", type);

    if (m_code > 0)
        helperToXmlAddAttribute(writer, "code", QString::number(m_code));

    if(!cond.isEmpty())
    {
        writer->writeStartElement(cond);
        helperToXmlAddAttribute(writer,"xmlns", ns_stanza);
        writer->writeEndElement();
    }
    if(!m_text.isEmpty())
    {
        writer->writeStartElement("text");
        helperToXmlAddAttribute(writer,"xml:lang", "en");
        helperToXmlAddAttribute(writer,"xmlns", ns_stanza);
        writer->writeCharacters(m_text);
        writer->writeEndElement();
    }

    writer->writeEndElement();
}

QXmppStanza::QXmppStanza(const QString& from, const QString& to) : QXmppPacket(),
m_to(to), m_from(from)
{
}

QXmppStanza::~QXmppStanza()
{
}

QString QXmppStanza::to() const
{
    return m_to;
}

void QXmppStanza::setTo(const QString& to)
{
    m_to = to;
}

QString QXmppStanza::from() const
{
    return m_from;
}

void QXmppStanza::setFrom(const QString& from)
{
    m_from = from;
}

QString QXmppStanza::id() const
{
    return m_id;
}

void QXmppStanza::setId(const QString& id)
{
    m_id = id;
}

QString QXmppStanza::lang() const
{
    return m_lang;
}

void QXmppStanza::setLang(const QString& lang)
{
    m_lang = lang;
}

QXmppStanza::Error QXmppStanza::error() const
{
    return m_error;
}

void QXmppStanza::setError(QXmppStanza::Error& error)
{
    m_error = error;
}

QXmppElementList QXmppStanza::extensions() const
{
    return m_extensions;
}

void QXmppStanza::setExtensions(const QXmppElementList &extensions)
{
    m_extensions = extensions;
}

void QXmppStanza::generateAndSetNextId()
{
    // get back
    ++s_uniqeIdNo;
    m_id = "qxmpp" + QString::number(s_uniqeIdNo);
}

bool QXmppStanza::isErrorStanza()
{
    return m_error.isValid();
}

void QXmppStanza::parse(const QDomElement &element)
{
    m_from = element.attribute("from");
    m_to = element.attribute("to");
    m_id = element.attribute("id");
    m_lang = element.attribute("lang");

    QDomElement errorElement = element.firstChildElement("error");
    if(!errorElement.isNull())
        m_error.parse(errorElement);
}

// deprecated

QString QXmppStanza::getTo() const
{
    return m_to;
}

QString QXmppStanza::getFrom() const
{
    return m_from;
}

QString QXmppStanza::getId() const
{
    return m_id;
}

QString QXmppStanza::getLang() const
{
    return m_lang;
}

QXmppStanza::Error QXmppStanza::getError() const
{
    return m_error;
}

<commit_msg>cleanup QXmppStanza::Error API<commit_after>/*
 * Copyright (C) 2008-2009 Manjeet Dahiya
 *
 * Author:
 *	Manjeet Dahiya
 *
 * Source:
 *	http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * 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.
 *
 */

#include "QXmppStanza.h"
#include "QXmppUtils.h"
#include "QXmppConstants.h"

#include <QDomElement>
#include <QXmlStreamWriter>

uint QXmppStanza::s_uniqeIdNo = 0;

QXmppStanza::Error::Error():
    m_code(0),
    m_type(static_cast<QXmppStanza::Error::Type>(-1)),
    m_condition(static_cast<QXmppStanza::Error::Condition>(-1)),
    m_text("")
{
}

QXmppStanza::Error::Error(Type type, Condition cond, const QString& text):
    m_code(0),
    m_type(type),
    m_condition(cond),
    m_text(text)
{
}

QXmppStanza::Error::Error(const QString& type, const QString& cond,
                          const QString& text):
    m_code(0),
    m_text(text)
{
    setTypeFromStr(type);
    setConditionFromStr(cond);
}

QString QXmppStanza::Error::text() const
{
    return m_text;
}

void QXmppStanza::Error::setText(const QString& text)
{
    m_text = text;
}

int QXmppStanza::Error::code() const
{
    return m_code;
}

void QXmppStanza::Error::setCode(int code)
{
    m_code = code;
}

QXmppStanza::Error::Condition QXmppStanza::Error::condition() const
{
    return m_condition;
}

void QXmppStanza::Error::setCondition(QXmppStanza::Error::Condition cond)
{
    m_condition = cond;
}

QXmppStanza::Error::Type QXmppStanza::Error::type() const
{
    return m_type;
}

void QXmppStanza::Error::setType(QXmppStanza::Error::Type type)
{
    m_type = type;
}

QString QXmppStanza::Error::getTypeStr() const
{
    switch(m_type)
    {
    case Cancel:
        return "cancel";
    case Continue:
        return "continue";
    case Modify:
        return "modify";
    case Auth:
        return "auth";
    case Wait:
        return "wait";
    default:
        return "";
    }
}

QString QXmppStanza::Error::getConditionStr() const
{
    switch(m_condition)
    {
    case BadRequest:
        return "bad-request";
    case Conflict:
        return "conflict";
    case FeatureNotImplemented:
        return "feature-not-implemented";
    case Forbidden:
        return "forbidden";
    case Gone:
        return "gone";
    case InternalServerError:
        return "internal-server-error";
    case ItemNotFound:
        return "item-not-found";
    case JidMalformed:
        return "jid-malformed";
    case NotAcceptable:
        return "not-acceptable";
    case NotAllowed:
        return "not-allowed";
    case NotAuthorized:
        return "not-authorized";
    case PaymentRequired:
        return "payment-required";
    case RecipientUnavailable:
        return "recipient-unavailable";
    case Redirect:
        return "redirect";
    case RegistrationRequired:
        return "registration-required";
    case RemoteServerNotFound:
        return "remote-server-not-found";
    case RemoteServerTimeout:
        return "remote-server-timeout";
    case ResourceConstraint:
        return "resource-constraint";
    case ServiceUnavailable:
        return "service-unavailable";
    case SubscriptionRequired:
        return "subscription-required";
    case UndefinedCondition:
        return "undefined-condition";
    case UnexpectedRequest:
        return "unexpected-request";
    default:
        return "";
    }
}

void QXmppStanza::Error::setTypeFromStr(const QString& type)
{
    if(type == "cancel")
        setType(Cancel);
    else if(type == "continue")
        setType(Continue);
    else if(type == "modify")
        setType(Modify);
    else if(type == "auth")
        setType(Auth);
    else if(type == "wait")
        setType(Wait);
    else
        setType(static_cast<QXmppStanza::Error::Type>(-1));
}

void QXmppStanza::Error::setConditionFromStr(const QString& type)
{
    if(type == "bad-request")
        setCondition(BadRequest);
    else if(type == "conflict")
        setCondition(Conflict);
    else if(type == "feature-not-implemented")
        setCondition(FeatureNotImplemented);
    else if(type == "forbidden")
        setCondition(Forbidden);
    else if(type == "gone")
        setCondition(Gone);
    else if(type == "internal-server-error")
        setCondition(InternalServerError);
    else if(type == "item-not-found")
        setCondition(ItemNotFound);
    else if(type == "jid-malformed")
        setCondition(JidMalformed);
    else if(type == "not-acceptable")
        setCondition(NotAcceptable);
    else if(type == "not-allowed")
        setCondition(NotAllowed);
    else if(type == "not-authorized")
        setCondition(NotAuthorized);
    else if(type == "payment-required")
        setCondition(PaymentRequired);
    else if(type == "recipient-unavailable")
        setCondition(RecipientUnavailable);
    else if(type == "redirect")
        setCondition(Redirect);
    else if(type == "registration-required")
        setCondition(RegistrationRequired);
    else if(type == "remote-server-not-found")
        setCondition(RemoteServerNotFound);
    else if(type == "remote-server-timeout")
        setCondition(RemoteServerTimeout);
    else if(type == "resource-constraint")
        setCondition(ResourceConstraint);
    else if(type == "service-unavailable")
        setCondition(ServiceUnavailable);
    else if(type == "subscription-required")
        setCondition(SubscriptionRequired);
    else if(type == "undefined-condition")
        setCondition(UndefinedCondition);
    else if(type == "unexpected-request")
        setCondition(UnexpectedRequest);
    else
        setCondition(static_cast<QXmppStanza::Error::Condition>(-1));
}

bool QXmppStanza::Error::isValid()
{
    return !(getTypeStr().isEmpty() && getConditionStr().isEmpty());
}

void QXmppStanza::Error::parse(const QDomElement &errorElement)
{
    setCode(errorElement.attribute("code").toInt());
    setTypeFromStr(errorElement.attribute("type"));

    QString text;
    QString cond;
    QDomElement element = errorElement.firstChildElement();
    while(!element.isNull())
    {
        if(element.tagName() == "text")
            text = element.text();
        else if(element.namespaceURI() == ns_stanza)
        {
            cond = element.tagName();
        }
        element = element.nextSiblingElement();
    }

    setConditionFromStr(cond);
    setText(text);
}

void QXmppStanza::Error::toXml( QXmlStreamWriter *writer ) const
{
    QString cond = getConditionStr();
    QString type = getTypeStr();

    if(cond.isEmpty() && type.isEmpty())
        return;

    writer->writeStartElement("error");
    helperToXmlAddAttribute(writer, "type", type);

    if (m_code > 0)
        helperToXmlAddAttribute(writer, "code", QString::number(m_code));

    if(!cond.isEmpty())
    {
        writer->writeStartElement(cond);
        helperToXmlAddAttribute(writer,"xmlns", ns_stanza);
        writer->writeEndElement();
    }
    if(!m_text.isEmpty())
    {
        writer->writeStartElement("text");
        helperToXmlAddAttribute(writer,"xml:lang", "en");
        helperToXmlAddAttribute(writer,"xmlns", ns_stanza);
        writer->writeCharacters(m_text);
        writer->writeEndElement();
    }

    writer->writeEndElement();
}

QXmppStanza::QXmppStanza(const QString& from, const QString& to) : QXmppPacket(),
m_to(to), m_from(from)
{
}

QXmppStanza::~QXmppStanza()
{
}

QString QXmppStanza::to() const
{
    return m_to;
}

void QXmppStanza::setTo(const QString& to)
{
    m_to = to;
}

QString QXmppStanza::from() const
{
    return m_from;
}

void QXmppStanza::setFrom(const QString& from)
{
    m_from = from;
}

QString QXmppStanza::id() const
{
    return m_id;
}

void QXmppStanza::setId(const QString& id)
{
    m_id = id;
}

QString QXmppStanza::lang() const
{
    return m_lang;
}

void QXmppStanza::setLang(const QString& lang)
{
    m_lang = lang;
}

QXmppStanza::Error QXmppStanza::error() const
{
    return m_error;
}

void QXmppStanza::setError(QXmppStanza::Error& error)
{
    m_error = error;
}

QXmppElementList QXmppStanza::extensions() const
{
    return m_extensions;
}

void QXmppStanza::setExtensions(const QXmppElementList &extensions)
{
    m_extensions = extensions;
}

void QXmppStanza::generateAndSetNextId()
{
    // get back
    ++s_uniqeIdNo;
    m_id = "qxmpp" + QString::number(s_uniqeIdNo);
}

bool QXmppStanza::isErrorStanza()
{
    return m_error.isValid();
}

void QXmppStanza::parse(const QDomElement &element)
{
    m_from = element.attribute("from");
    m_to = element.attribute("to");
    m_id = element.attribute("id");
    m_lang = element.attribute("lang");

    QDomElement errorElement = element.firstChildElement("error");
    if(!errorElement.isNull())
        m_error.parse(errorElement);
}

// deprecated

QString QXmppStanza::Error::getText() const
{
    return m_text;
}

int QXmppStanza::Error::getCode() const
{
    return m_code;
}

QXmppStanza::Error::Condition QXmppStanza::Error::getCondition() const
{
    return m_condition;
}

QXmppStanza::Error::Type QXmppStanza::Error::getType() const
{
    return m_type;
}

QString QXmppStanza::getTo() const
{
    return m_to;
}

QString QXmppStanza::getFrom() const
{
    return m_from;
}

QString QXmppStanza::getId() const
{
    return m_id;
}

QString QXmppStanza::getLang() const
{
    return m_lang;
}

QXmppStanza::Error QXmppStanza::getError() const
{
    return m_error;
}

<|endoftext|>


<commit_before><commit_msg>Change the Linux sad tab message wrapping to match Windows.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "client/windows/crash_generation/minidump_generator.h"
#include <cassert>
#include "client/windows/common/auto_critical_section.h"
#include "common/windows/guid_string.h"

using std::wstring;

namespace google_breakpad {

MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
    : dbghelp_module_(NULL),
      rpcrt4_module_(NULL),
      dump_path_(dump_path),
      write_dump_(NULL),
      create_uuid_(NULL) {
  InitializeCriticalSection(&module_load_sync_);
  InitializeCriticalSection(&get_proc_address_sync_);
}

MinidumpGenerator::~MinidumpGenerator() {
  if (dbghelp_module_) {
    FreeLibrary(dbghelp_module_);
  }

  if (rpcrt4_module_) {
    FreeLibrary(rpcrt4_module_);
  }

  DeleteCriticalSection(&get_proc_address_sync_);
  DeleteCriticalSection(&module_load_sync_);
}

bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
                                      DWORD process_id,
                                      DWORD thread_id,
                                      DWORD requesting_thread_id,
                                      EXCEPTION_POINTERS* exception_pointers,
                                      MDRawAssertionInfo* assert_info,
                                      MINIDUMP_TYPE dump_type,
                                      bool is_client_pointers,
                                      wstring* dump_path) {
  MiniDumpWriteDumpType write_dump = GetWriteDump();
  if (!write_dump) {
    return false;
  }

  wstring dump_file_path;
  if (!GenerateDumpFilePath(&dump_file_path)) {
    return false;
  }

  HANDLE dump_file = CreateFile(dump_file_path.c_str(),
                                GENERIC_WRITE,
                                0,
                                NULL,
                                CREATE_NEW,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);

  if (dump_file == INVALID_HANDLE_VALUE) {
    return false;
  }

  MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
  MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;

  // Setup the exception information object only if it's a dump
  // due to an exception.
  if (exception_pointers) {
    dump_exception_pointers = &dump_exception_info;
    dump_exception_info.ThreadId = thread_id;
    dump_exception_info.ExceptionPointers = exception_pointers;
    dump_exception_info.ClientPointers = is_client_pointers;
  }

  // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
  // information about the exception handler to the Breakpad processor.
  // The information will help the processor determine which threads are
  // relevant. The Breakpad processor does not require this information but
  // can function better with Breakpad-generated dumps when it is present.
  // The native debugger is not harmed by the presence of this information.
  MDRawBreakpadInfo breakpad_info;
  breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
                           MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
  breakpad_info.dump_thread_id = thread_id;
  breakpad_info.requesting_thread_id = requesting_thread_id;

  // Leave room in user_stream_array for a possible assertion info stream.
  MINIDUMP_USER_STREAM user_stream_array[2];
  user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
  user_stream_array[0].BufferSize = sizeof(breakpad_info);
  user_stream_array[0].Buffer = &breakpad_info;

  MINIDUMP_USER_STREAM_INFORMATION user_streams;
  user_streams.UserStreamCount = 1;
  user_streams.UserStreamArray = user_stream_array;

  MDRawAssertionInfo* actual_assert_info = assert_info;
  MDRawAssertionInfo client_assert_info = {0};

  if (assert_info) {
    // If the assertion info object lives in the client process,
    // read the memory of the client process.
    if (is_client_pointers) {
      SIZE_T bytes_read = 0;
      if (!ReadProcessMemory(process_handle,
                             assert_info,
                             &client_assert_info,
                             sizeof(client_assert_info),
                             &bytes_read)) {
        CloseHandle(dump_file);
        return false;
      }

      if (bytes_read != sizeof(client_assert_info)) {
        CloseHandle(dump_file);
        return false;
      }

      actual_assert_info  = &client_assert_info;
    }

    user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
    user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
    user_stream_array[1].Buffer = actual_assert_info;
    ++user_streams.UserStreamCount;
  }

  bool result = write_dump(process_handle,
                           process_id,
                           dump_file,
                           dump_type,
                           exception_pointers ? &dump_exception_info : NULL,
                           &user_streams,
                           NULL) != FALSE;

  CloseHandle(dump_file);

  // Store the path of the dump file in the out parameter if dump generation
  // succeeded.
  if (result && dump_path) {
    *dump_path = dump_file_path;
  }

  return result;
}

HMODULE MinidumpGenerator::GetDbghelpModule() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!dbghelp_module_) {
    dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
  }

  return dbghelp_module_;
}

MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
  AutoCriticalSection lock(&get_proc_address_sync_);
  if (!write_dump_) {
    HMODULE module = GetDbghelpModule();
    if (module) {
      FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
      write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
    }
  }

  return write_dump_;
}

HMODULE MinidumpGenerator::GetRpcrt4Module() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!rpcrt4_module_) {
    rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
  }

  return rpcrt4_module_;
}

MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!create_uuid_) {
    HMODULE module = GetRpcrt4Module();
    if (module) {
      FARPROC proc = GetProcAddress(module, "UuidCreate");
      create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
    }
  }

  return create_uuid_;
}

bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
  UUID id = {0};

  UuidCreateType create_uuid = GetCreateUuid();
  if(!create_uuid) {
    return false;
  }

  create_uuid(&id);
  wstring id_str = GUIDString::GUIDToWString(&id);

  *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
  return true;
}

}  // namespace google_breakpad
<commit_msg><commit_after>// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "client/windows/crash_generation/minidump_generator.h"
#include <cassert>
#include "client/windows/common/auto_critical_section.h"
#include "common/windows/guid_string.h"

using std::wstring;

namespace google_breakpad {

MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
    : dbghelp_module_(NULL),
      rpcrt4_module_(NULL),
      dump_path_(dump_path),
      write_dump_(NULL),
      create_uuid_(NULL) {
  InitializeCriticalSection(&module_load_sync_);
  InitializeCriticalSection(&get_proc_address_sync_);
}

MinidumpGenerator::~MinidumpGenerator() {
  if (dbghelp_module_) {
    FreeLibrary(dbghelp_module_);
  }

  if (rpcrt4_module_) {
    FreeLibrary(rpcrt4_module_);
  }

  DeleteCriticalSection(&get_proc_address_sync_);
  DeleteCriticalSection(&module_load_sync_);
}

bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
                                      DWORD process_id,
                                      DWORD thread_id,
                                      DWORD requesting_thread_id,
                                      EXCEPTION_POINTERS* exception_pointers,
                                      MDRawAssertionInfo* assert_info,
                                      MINIDUMP_TYPE dump_type,
                                      bool is_client_pointers,
                                      wstring* dump_path) {
  MiniDumpWriteDumpType write_dump = GetWriteDump();
  if (!write_dump) {
    return false;
  }

  wstring dump_file_path;
  if (!GenerateDumpFilePath(&dump_file_path)) {
    return false;
  }

  HANDLE dump_file = CreateFile(dump_file_path.c_str(),
                                GENERIC_WRITE,
                                0,
                                NULL,
                                CREATE_NEW,
                                FILE_ATTRIBUTE_NORMAL,
                                NULL);

  if (dump_file == INVALID_HANDLE_VALUE) {
    return false;
  }

  MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
  MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;

  // Setup the exception information object only if it's a dump
  // due to an exception.
  if (exception_pointers) {
    dump_exception_pointers = &dump_exception_info;
    dump_exception_info.ThreadId = thread_id;
    dump_exception_info.ExceptionPointers = exception_pointers;
    dump_exception_info.ClientPointers = is_client_pointers;
  }

  // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
  // information about the exception handler to the Breakpad processor.
  // The information will help the processor determine which threads are
  // relevant. The Breakpad processor does not require this information but
  // can function better with Breakpad-generated dumps when it is present.
  // The native debugger is not harmed by the presence of this information.
  MDRawBreakpadInfo breakpad_info = {0};
  if (!is_client_pointers) {
    // Set the dump thread id and requesting thread id only in case of
    // in-process dump generation.
    breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
                             MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
    breakpad_info.dump_thread_id = thread_id;
    breakpad_info.requesting_thread_id = requesting_thread_id;
  }

  // Leave room in user_stream_array for a possible assertion info stream.
  MINIDUMP_USER_STREAM user_stream_array[2];
  user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
  user_stream_array[0].BufferSize = sizeof(breakpad_info);
  user_stream_array[0].Buffer = &breakpad_info;

  MINIDUMP_USER_STREAM_INFORMATION user_streams;
  user_streams.UserStreamCount = 1;
  user_streams.UserStreamArray = user_stream_array;

  MDRawAssertionInfo* actual_assert_info = assert_info;
  MDRawAssertionInfo client_assert_info = {0};

  if (assert_info) {
    // If the assertion info object lives in the client process,
    // read the memory of the client process.
    if (is_client_pointers) {
      SIZE_T bytes_read = 0;
      if (!ReadProcessMemory(process_handle,
                             assert_info,
                             &client_assert_info,
                             sizeof(client_assert_info),
                             &bytes_read)) {
        CloseHandle(dump_file);
        return false;
      }

      if (bytes_read != sizeof(client_assert_info)) {
        CloseHandle(dump_file);
        return false;
      }

      actual_assert_info  = &client_assert_info;
    }

    user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
    user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
    user_stream_array[1].Buffer = actual_assert_info;
    ++user_streams.UserStreamCount;
  }

  bool result = write_dump(process_handle,
                           process_id,
                           dump_file,
                           dump_type,
                           exception_pointers ? &dump_exception_info : NULL,
                           &user_streams,
                           NULL) != FALSE;

  CloseHandle(dump_file);

  // Store the path of the dump file in the out parameter if dump generation
  // succeeded.
  if (result && dump_path) {
    *dump_path = dump_file_path;
  }

  return result;
}

HMODULE MinidumpGenerator::GetDbghelpModule() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!dbghelp_module_) {
    dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
  }

  return dbghelp_module_;
}

MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
  AutoCriticalSection lock(&get_proc_address_sync_);
  if (!write_dump_) {
    HMODULE module = GetDbghelpModule();
    if (module) {
      FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
      write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
    }
  }

  return write_dump_;
}

HMODULE MinidumpGenerator::GetRpcrt4Module() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!rpcrt4_module_) {
    rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
  }

  return rpcrt4_module_;
}

MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
  AutoCriticalSection lock(&module_load_sync_);
  if (!create_uuid_) {
    HMODULE module = GetRpcrt4Module();
    if (module) {
      FARPROC proc = GetProcAddress(module, "UuidCreate");
      create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
    }
  }

  return create_uuid_;
}

bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
  UUID id = {0};

  UuidCreateType create_uuid = GetCreateUuid();
  if(!create_uuid) {
    return false;
  }

  create_uuid(&id);
  wstring id_str = GUIDString::GUIDToWString(&id);

  *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
  return true;
}

}  // namespace google_breakpad
<|endoftext|>


<commit_before><commit_msg>Prediction: implement build adc trajectory<commit_after><|endoftext|>