<commit_before>#include "common.h"
#include "eventdispatcher_libevent.h"
#include "eventdispatcher_libevent_p.h"

/**
 * @class EventDispatcherLibEvent
 * @brief The EventDispatcherLibEvent class provides an interface to manage Qt's event queue.
 *
 * An event dispatcher receives events from the window system and other
 * sources. It then sends them to the QCoreApplication or QApplication
 * instance for processing and delivery. EventDispatcherLibEvent provides
 * fine-grained control over event delivery.
 *
 * For simple control of event processing use
 * QCoreApplication::processEvents().
 *
 * For finer control of the application's event loop, call
 * instance() and call functions on the QAbstractEventDispatcher
 * object that is returned.
 *
 * To use EventDispatcherLibEvent, you must install it with
 * QCoreApplication::setEventDispatcher() or QThread::setEventDispatcher()
 * before a default event dispatcher has been installed.

 * The main event loop is started by calling
 * QCoreApplication::exec(), and stopped by calling
 * QCoreApplication::exit(). Local event loops can be created using
 * QEventLoop.
 *
 * Programs that perform long operations can call processEvents()
 * with a bitwise OR combination of various QEventLoop::ProcessEventsFlag
 * values to control which events should be delivered.
 */

/**
 * Constructs a new event dispatcher with the given @a parent
 *
 * @param parent Parent
 */
EventDispatcherLibEvent::EventDispatcherLibEvent(QObject* parent)
	: QAbstractEventDispatcher(parent), d_ptr(new EventDispatcherLibEventPrivate(this))
{
}

/**
 * Constructs a new event dispatcher with the given configuration @a config and @a parent
 *
 * @param config Event dispatcher configuration
 * @param parent Parent
 * @see EventDispatcherLibEventConfig
 */
EventDispatcherLibEvent::EventDispatcherLibEvent(const EventDispatcherLibEventConfig& config, QObject* parent)
	: QAbstractEventDispatcher(parent), d_ptr(new EventDispatcherLibEventPrivate(this, config))
{
}

/**
 * Destroys the event dispatcher
 */
EventDispatcherLibEvent::~EventDispatcherLibEvent(void)
{
#if QT_VERSION < 0x040600
	delete this->d_ptr;
	this->d_ptr = 0;
#endif
}

/**
 * Retrieve the libevent event_base for this dispatcher
 * @return The event_base for this dispatcher
 */
struct event_base* EventDispatcherLibEvent::eventBase() const
{
	const Q_D(EventDispatcherLibEvent);
	return d->eventBase();
}

/**
 * @brief Processes pending events that match @a flags until there are no more events to process
 * @param flags
 * @return Whether an event has been processed
 * @retval true If an event has been processed;
 * @retval false If no events have been processed
 *
 * Processes pending events that match @a flags until there are no
 * more events to process. Returns true if an event was processed;
 * otherwise returns false.
 *
 * This function is especially useful if you have a long running
 * operation and want to show its progress without allowing user
 * input; i.e. by using the QEventLoop::ExcludeUserInputEvents flag.
 *
 * If the QEventLoop::WaitForMoreEvents flag is set in @a flags, the
 * behavior of this function is as follows:
 *
 * @list
 * @li If events are available, this function returns after processing them.
 * @li If no events are available, this function will wait until more
 * are available and return after processing newly available events.
 * @endlist
 *
 * If the QEventLoop::WaitForMoreEvents flag is not set in @a flags,
 * and no events are available, this function will return
 * immediately.
 *
 * @note This function does not process events continuously; it
 * returns after all available events are processed.
 *
 * @see hasPendingEvents()
 */
bool EventDispatcherLibEvent::processEvents(QEventLoop::ProcessEventsFlags flags)
{
	Q_D(EventDispatcherLibEvent);
	return d->processEvents(flags);
}

/**
 * Returns @c true if there is an event waiting; otherwise returns @c false
 *
 * @return Whether there is an event waiting
 */
bool EventDispatcherLibEvent::hasPendingEvents(void)
{
	extern uint qGlobalPostedEventsCount();
	return qGlobalPostedEventsCount() > 0;
}

/**
 * Registers @a notifier with the event loop
 *
 * @param notifier Socket notifier to register
 * @warning @a notifier must belong to the same thread as the event dispatcher
 * @warning Socket notifiers can only be enabled from the thread they belong to
 */
void EventDispatcherLibEvent::registerSocketNotifier(QSocketNotifier* notifier)
{
#ifndef QT_NO_DEBUG
	if (notifier->socket() < 0) {
		qWarning("QSocketNotifier: Internal error: sockfd < 0");
		return;
	}

	if (notifier->thread() != this->thread() || this->thread() != QThread::currentThread()) {
		qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
		return;
	}
#endif

	if (notifier->type() == QSocketNotifier::Exception) {
		return;
	}

	Q_D(EventDispatcherLibEvent);
	d->registerSocketNotifier(notifier);
}

/**
 * Unregisters @a notifier from the event dispatcher.
 *
 * @param notifier Socket notifier to unregister
 * @warning @a notifier must belong to the same thread as the event dispatcher
 * @warning Socket notifiers can only be disabled from the thread they belong to
 */
void EventDispatcherLibEvent::unregisterSocketNotifier(QSocketNotifier* notifier)
{
#ifndef QT_NO_DEBUG
	if (notifier->socket() < 0) {
		qWarning("QSocketNotifier: Internal error: sockfd < 0");
		return;
	}

	if (notifier->thread() != this->thread() || this->thread() != QThread::currentThread()) {
		qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
		return;
	}
#endif

	// Short circuit, we do not support QSocketNotifier::Exception
	if (notifier->type() == QSocketNotifier::Exception) {
		return;
	}

	Q_D(EventDispatcherLibEvent);
	d->unregisterSocketNotifier(notifier);
}

/**
 * Register a timer with the specified @a timerId, @a interval, and @a timerType
 * for the given @a object.
 *
 * @param timerId Timer ID
 * @param interval Timer interval (msec); must be greater than 0
 * @param timerType Timer type (not available in Qt 4)
 * @param object Object for which the timer is registered
 * @warning @a object must belong to the same thread as the event dispatcher
 * @warning Timers can only be started from the thread the event dispatcher lives in
 */
void EventDispatcherLibEvent::registerTimer(
	int timerId,
	int interval,
#if QT_VERSION >= 0x050000
	Qt::TimerType timerType,
#endif
	QObject* object
)
{
#ifndef QT_NO_DEBUG
	if (timerId < 1 || interval < 0 || !object) {
		qWarning("%s: invalid arguments", Q_FUNC_INFO);
		return;
	}

	if (object->thread() != this->thread() && this->thread() != QThread::currentThread()) {
		qWarning("%s: timers cannot be started from another thread", Q_FUNC_INFO);
		return;
	}
#endif

	Qt::TimerType type;
#if QT_VERSION >= 0x050000
	type = timerType;
#else
	type = Qt::CoarseTimer;
#endif

	Q_D(EventDispatcherLibEvent);
	d->registerTimer(timerId, interval, type, object);
}

/**
 * Unregisters the timer
 *
 * @param timerId ID of the timer
 * @return Whether the timer has been unregistered
 * @warning Timers can only be stopped from the same thread as the event dispatcher lives in
 */
bool EventDispatcherLibEvent::unregisterTimer(int timerId)
{
#ifndef QT_NO_DEBUG
	if (timerId < 1) {
		qWarning("%s: invalid arguments", Q_FUNC_INFO);
		return false;
	}

	if (this->thread() != QThread::currentThread()) {
		qWarning("%s: timers cannot be stopped from another thread", Q_FUNC_INFO);
		return false;
	}
#endif

	Q_D(EventDispatcherLibEvent);
	return d->unregisterTimer(timerId);
}

/**
 * Unregisters all timers for the given @a object
 *
 * @param object Object
 * @return Whether timers have been unregistered
 * @warning @a object must belong to the same thread as the event dispatcher
 * @warning Timers can only be started from the thread the event dispatcher lives in
 */
bool EventDispatcherLibEvent::unregisterTimers(QObject* object)
{
#ifndef QT_NO_DEBUG
	if (!object) {
		qWarning("%s: invalid arguments", Q_FUNC_INFO);
		return false;
	}

	if (object->thread() != this->thread() && this->thread() != QThread::currentThread()) {
		qWarning("%s: timers cannot be stopped from another thread", Q_FUNC_INFO);
		return false;
	}
#endif

	Q_D(EventDispatcherLibEvent);
	return d->unregisterTimers(object);
}

/**
 * @brief Returns a list of registered timers for the given @a object.
 * @param object Object
 * @return List of registered timers
 */
QList<QAbstractEventDispatcher::TimerInfo> EventDispatcherLibEvent::registeredTimers(QObject* object) const
{
	if (!object) {
		qWarning("%s: invalid argument", Q_FUNC_INFO);
		return QList<QAbstractEventDispatcher::TimerInfo>();
	}

	Q_D(const EventDispatcherLibEvent);
	return d->registeredTimers(object);
}

#if QT_VERSION >= 0x050000
/**
 * Returns the remaining time in milliseconds with the given @a timerId.
 *
 * @param timerId Timer ID
 * @return The remaining time
 * @retval -1 If the timer is inactive
 * @retval 0 If the timer is overdue
 */
int EventDispatcherLibEvent::remainingTime(int timerId)
{
	Q_D(const EventDispatcherLibEvent);
	return d->remainingTime(timerId);
}
#endif

#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
bool EventDispatcherLibEvent::registerEventNotifier(QWinEventNotifier* notifier)
{
	Q_UNUSED(notifier)
	Q_UNIMPLEMENTED();
	return false;
}

void EventDispatcherLibEvent::unregisterEventNotifier(QWinEventNotifier* notifier)
{
	Q_UNUSED(notifier)
	Q_UNIMPLEMENTED();
}
#endif

/**
 * Wakes up the event loop. Thread-safe
 */
void EventDispatcherLibEvent::wakeUp(void)
{
	Q_D(EventDispatcherLibEvent);
	d->m_tco->wakeUp();
}

/**
 * Interrupts event dispatching. The event dispatcher will return from @c processEvents()
 * as soon as possible.
 */
void EventDispatcherLibEvent::interrupt(void)
{
	Q_D(EventDispatcherLibEvent);
	d->m_interrupt = true;
	this->wakeUp();
}

/**
 * @brief Does nothing
 */
void EventDispatcherLibEvent::flush(void)
{
}

/**
 * @brief EventDispatcherLibEvent::EventDispatcherLibEvent
 * @param dd
 * @param parent
 * @internal
 */
EventDispatcherLibEvent::EventDispatcherLibEvent(EventDispatcherLibEventPrivate& dd, QObject* parent)
	: QAbstractEventDispatcher(parent), d_ptr(&dd)
{
}

void EventDispatcherLibEvent::reinitialize(void)
{
	Q_D(EventDispatcherLibEvent);
	event_reinit(d->m_base);
}

/**
 * @fn void EventDispatcherLibEvent::awake()
 *
 * This signal is emitted after the event loop returns from a function that could block.
 *
 * @see wakeUp()
 * @see aboutToBlock()
 */

/**
 * @fn void EventDispatcherLibEvent::aboutToBlock()
 *
 * This signal is emitted before the event loop calls a function that could block.
 *
 * @see awake()
 */
<commit_msg>Update eventdispatcher_libevent.cpp<commit_after>#include "common.h"
#include "eventdispatcher_libevent.h"
#include "eventdispatcher_libevent_p.h"

/**
 * @class EventDispatcherLibEvent
 * @brief The EventDispatcherLibEvent class provides an interface to manage Qt's event queue.
 *
 * An event dispatcher receives events from the window system and other
 * sources. It then sends them to the QCoreApplication or QApplication
 * instance for processing and delivery. EventDispatcherLibEvent provides
 * fine-grained control over event delivery.
 *
 * For simple control of event processing use
 * QCoreApplication::processEvents().
 *
 * For finer control of the application's event loop, call
 * instance() and call functions on the QAbstractEventDispatcher
 * object that is returned.
 *
 * To use EventDispatcherLibEvent, you must install it with
 * QCoreApplication::setEventDispatcher() or QThread::setEventDispatcher()
 * before a default event dispatcher has been installed.

 * The main event loop is started by calling
 * QCoreApplication::exec(), and stopped by calling
 * QCoreApplication::exit(). Local event loops can be created using
 * QEventLoop.
 *
 * Programs that perform long operations can call processEvents()
 * with a bitwise OR combination of various QEventLoop::ProcessEventsFlag
 * values to control which events should be delivered.
 */

/**
 * Constructs a new event dispatcher with the given @a parent
 *
 * @param parent Parent
 */
EventDispatcherLibEvent::EventDispatcherLibEvent(QObject* parent)
	: QAbstractEventDispatcher(parent), d_ptr(new EventDispatcherLibEventPrivate(this))
{
}

/**
 * Constructs a new event dispatcher with the given configuration @a config and @a parent
 *
 * @param config Event dispatcher configuration
 * @param parent Parent
 * @see EventDispatcherLibEventConfig
 */
EventDispatcherLibEvent::EventDispatcherLibEvent(const EventDispatcherLibEventConfig& config, QObject* parent)
	: QAbstractEventDispatcher(parent), d_ptr(new EventDispatcherLibEventPrivate(this, config))
{
}

/**
 * Destroys the event dispatcher
 */
EventDispatcherLibEvent::~EventDispatcherLibEvent(void)
{
#if QT_VERSION < 0x040600
	delete this->d_ptr;
	this->d_ptr = 0;
#endif
}

/**
 * Retrieve the libevent event_base for this dispatcher
 * @return The event_base for this dispatcher
 */
struct event_base* EventDispatcherLibEvent::eventBase(void) const
{
	const Q_D(EventDispatcherLibEvent);
	return d->eventBase();
}

/**
 * @brief Processes pending events that match @a flags until there are no more events to process
 * @param flags
 * @return Whether an event has been processed
 * @retval true If an event has been processed;
 * @retval false If no events have been processed
 *
 * Processes pending events that match @a flags until there are no
 * more events to process. Returns true if an event was processed;
 * otherwise returns false.
 *
 * This function is especially useful if you have a long running
 * operation and want to show its progress without allowing user
 * input; i.e. by using the QEventLoop::ExcludeUserInputEvents flag.
 *
 * If the QEventLoop::WaitForMoreEvents flag is set in @a flags, the
 * behavior of this function is as follows:
 *
 * @list
 * @li If events are available, this function returns after processing them.
 * @li If no events are available, this function will wait until more
 * are available and return after processing newly available events.
 * @endlist
 *
 * If the QEventLoop::WaitForMoreEvents flag is not set in @a flags,
 * and no events are available, this function will return
 * immediately.
 *
 * @note This function does not process events continuously; it
 * returns after all available events are processed.
 *
 * @see hasPendingEvents()
 */
bool EventDispatcherLibEvent::processEvents(QEventLoop::ProcessEventsFlags flags)
{
	Q_D(EventDispatcherLibEvent);
	return d->processEvents(flags);
}

/**
 * Returns @c true if there is an event waiting; otherwise returns @c false
 *
 * @return Whether there is an event waiting
 */
bool EventDispatcherLibEvent::hasPendingEvents(void)
{
	extern uint qGlobalPostedEventsCount();
	return qGlobalPostedEventsCount() > 0;
}

/**
 * Registers @a notifier with the event loop
 *
 * @param notifier Socket notifier to register
 * @warning @a notifier must belong to the same thread as the event dispatcher
 * @warning Socket notifiers can only be enabled from the thread they belong to
 */
void EventDispatcherLibEvent::registerSocketNotifier(QSocketNotifier* notifier)
{
#ifndef QT_NO_DEBUG
	if (notifier->socket() < 0) {
		qWarning("QSocketNotifier: Internal error: sockfd < 0");
		return;
	}

	if (notifier->thread() != this->thread() || this->thread() != QThread::currentThread()) {
		qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
		return;
	}
#endif

	if (notifier->type() == QSocketNotifier::Exception) {
		return;
	}

	Q_D(EventDispatcherLibEvent);
	d->registerSocketNotifier(notifier);
}

/**
 * Unregisters @a notifier from the event dispatcher.
 *
 * @param notifier Socket notifier to unregister
 * @warning @a notifier must belong to the same thread as the event dispatcher
 * @warning Socket notifiers can only be disabled from the thread they belong to
 */
void EventDispatcherLibEvent::unregisterSocketNotifier(QSocketNotifier* notifier)
{
#ifndef QT_NO_DEBUG
	if (notifier->socket() < 0) {
		qWarning("QSocketNotifier: Internal error: sockfd < 0");
		return;
	}

	if (notifier->thread() != this->thread() || this->thread() != QThread::currentThread()) {
		qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
		return;
	}
#endif

	// Short circuit, we do not support QSocketNotifier::Exception
	if (notifier->type() == QSocketNotifier::Exception) {
		return;
	}

	Q_D(EventDispatcherLibEvent);
	d->unregisterSocketNotifier(notifier);
}

/**
 * Register a timer with the specified @a timerId, @a interval, and @a timerType
 * for the given @a object.
 *
 * @param timerId Timer ID
 * @param interval Timer interval (msec); must be greater than 0
 * @param timerType Timer type (not available in Qt 4)
 * @param object Object for which the timer is registered
 * @warning @a object must belong to the same thread as the event dispatcher
 * @warning Timers can only be started from the thread the event dispatcher lives in
 */
void EventDispatcherLibEvent::registerTimer(
	int timerId,
	int interval,
#if QT_VERSION >= 0x050000
	Qt::TimerType timerType,
#endif
	QObject* object
)
{
#ifndef QT_NO_DEBUG
	if (timerId < 1 || interval < 0 || !object) {
		qWarning("%s: invalid arguments", Q_FUNC_INFO);
		return;
	}

	if (object->thread() != this->thread() && this->thread() != QThread::currentThread()) {
		qWarning("%s: timers cannot be started from another thread", Q_FUNC_INFO);
		return;
	}
#endif

	Qt::TimerType type;
#if QT_VERSION >= 0x050000
	type = timerType;
#else
	type = Qt::CoarseTimer;
#endif

	Q_D(EventDispatcherLibEvent);
	d->registerTimer(timerId, interval, type, object);
}

/**
 * Unregisters the timer
 *
 * @param timerId ID of the timer
 * @return Whether the timer has been unregistered
 * @warning Timers can only be stopped from the same thread as the event dispatcher lives in
 */
bool EventDispatcherLibEvent::unregisterTimer(int timerId)
{
#ifndef QT_NO_DEBUG
	if (timerId < 1) {
		qWarning("%s: invalid arguments", Q_FUNC_INFO);
		return false;
	}

	if (this->thread() != QThread::currentThread()) {
		qWarning("%s: timers cannot be stopped from another thread", Q_FUNC_INFO);
		return false;
	}
#endif

	Q_D(EventDispatcherLibEvent);
	return d->unregisterTimer(timerId);
}

/**
 * Unregisters all timers for the given @a object
 *
 * @param object Object
 * @return Whether timers have been unregistered
 * @warning @a object must belong to the same thread as the event dispatcher
 * @warning Timers can only be started from the thread the event dispatcher lives in
 */
bool EventDispatcherLibEvent::unregisterTimers(QObject* object)
{
#ifndef QT_NO_DEBUG
	if (!object) {
		qWarning("%s: invalid arguments", Q_FUNC_INFO);
		return false;
	}

	if (object->thread() != this->thread() && this->thread() != QThread::currentThread()) {
		qWarning("%s: timers cannot be stopped from another thread", Q_FUNC_INFO);
		return false;
	}
#endif

	Q_D(EventDispatcherLibEvent);
	return d->unregisterTimers(object);
}

/**
 * @brief Returns a list of registered timers for the given @a object.
 * @param object Object
 * @return List of registered timers
 */
QList<QAbstractEventDispatcher::TimerInfo> EventDispatcherLibEvent::registeredTimers(QObject* object) const
{
	if (!object) {
		qWarning("%s: invalid argument", Q_FUNC_INFO);
		return QList<QAbstractEventDispatcher::TimerInfo>();
	}

	Q_D(const EventDispatcherLibEvent);
	return d->registeredTimers(object);
}

#if QT_VERSION >= 0x050000
/**
 * Returns the remaining time in milliseconds with the given @a timerId.
 *
 * @param timerId Timer ID
 * @return The remaining time
 * @retval -1 If the timer is inactive
 * @retval 0 If the timer is overdue
 */
int EventDispatcherLibEvent::remainingTime(int timerId)
{
	Q_D(const EventDispatcherLibEvent);
	return d->remainingTime(timerId);
}
#endif

#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
bool EventDispatcherLibEvent::registerEventNotifier(QWinEventNotifier* notifier)
{
	Q_UNUSED(notifier)
	Q_UNIMPLEMENTED();
	return false;
}

void EventDispatcherLibEvent::unregisterEventNotifier(QWinEventNotifier* notifier)
{
	Q_UNUSED(notifier)
	Q_UNIMPLEMENTED();
}
#endif

/**
 * Wakes up the event loop. Thread-safe
 */
void EventDispatcherLibEvent::wakeUp(void)
{
	Q_D(EventDispatcherLibEvent);
	d->m_tco->wakeUp();
}

/**
 * Interrupts event dispatching. The event dispatcher will return from @c processEvents()
 * as soon as possible.
 */
void EventDispatcherLibEvent::interrupt(void)
{
	Q_D(EventDispatcherLibEvent);
	d->m_interrupt = true;
	this->wakeUp();
}

/**
 * @brief Does nothing
 */
void EventDispatcherLibEvent::flush(void)
{
}

/**
 * @brief EventDispatcherLibEvent::EventDispatcherLibEvent
 * @param dd
 * @param parent
 * @internal
 */
EventDispatcherLibEvent::EventDispatcherLibEvent(EventDispatcherLibEventPrivate& dd, QObject* parent)
	: QAbstractEventDispatcher(parent), d_ptr(&dd)
{
}

void EventDispatcherLibEvent::reinitialize(void)
{
	Q_D(EventDispatcherLibEvent);
	event_reinit(d->m_base);
}

/**
 * @fn void EventDispatcherLibEvent::awake()
 *
 * This signal is emitted after the event loop returns from a function that could block.
 *
 * @see wakeUp()
 * @see aboutToBlock()
 */

/**
 * @fn void EventDispatcherLibEvent::aboutToBlock()
 *
 * This signal is emitted before the event loop calls a function that could block.
 *
 * @see awake()
 */
<|endoftext|>


<commit_before>/*
   Copyright 2012 Denys Sobchyshak

   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 <iostream>
#include "sorter.h"

//Performs a bubble sort on an array of ints.
void BubbleSort(int *array, int array_size){
    for (int i = 0; i<array_size; i++){
        bool swapped = false;
        for (int j = array_size; j>i; j--){
            if (array[j-1] > array[j]){
                int tmp = array[j-1];
                array[j-1] = array[j];
                array[j] = tmp;
                swapped = true;
            }
        }
        //-> invariant: array[0..i] is sorted and elements are in final position
        if (!swapped) break;
    }
};

//Performs an insertion sort on an array of ints.
void InsertionSort(int *array, int array_size){
    for (int i = 1; i < array_size; i++){
        int key = array[i];
        int j = i-1;
        while (j >= 0 && array[j] > key) {
            array[j+1] = array[j];
            j--;
        }
        array[j+1] = key;
        //-> invariant: array[0..j] is sorted
    }
};

//Performs a shell sort on an array of ints.
void ShellSort(int *array, int array_size){
    int h = 1;
    while (h < array_size) h = 3*h + 1;
    while (h > 0){
        h = h/3;
        for (int k = 0; k < h; k++){
            for (int i = h; i < array_size; i+=h){
                int key = array[i];
                int j = i-h;
                while (j>=0 && array[j] > key){
                    array[j+h] = array[j];
                    j-=h;
                }
                array[j+h] = key;
                //-> invariant: array[0..j] is sorted
            }
        }
        //->invariant: each h-sub-array is sorted
    }
};

//Performs a selection sort on an array of ints.
void SelectionSort(int *array, int array_size){
    for (int i = 0; i < array_size; i++){
        int iMin = i;

        for(int j = i+1; j < array_size; j++){
            if (array[iMin] > array[j]) iMin = j;
        }

        if (iMin != i){
            int tmp = array[i];
            array[i] = array[iMin];
            array[iMin] = tmp;
        }
        //->invariant: array[0...i] is sorted
    }
};

//Performs a heap sort on an array of ints.
void HeapSort(int *array, int array_size){

};

//Performs a merge sort on an array of ints.
void MergeSort(int *array, int array_size){

};

//Performs a quick sort on an array of ints.
void QuickSort(int *array, int array_size){
};<commit_msg>fixed shell sort bug<commit_after>/*
   Copyright 2012 Denys Sobchyshak

   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 <iostream>
#include "sorter.h"

//Performs a bubble sort on an array of ints.
void BubbleSort(int *array, int array_size){
    for (int i = 0; i<array_size; i++){
        bool swapped = false;
        for (int j = array_size; j>i; j--){
            if (array[j-1] > array[j]){
                int tmp = array[j-1];
                array[j-1] = array[j];
                array[j] = tmp;
                swapped = true;
            }
        }
        //-> invariant: array[0..i] is sorted and elements are in final position
        if (!swapped) break;
    }
};

//Performs an insertion sort on an array of ints.
void InsertionSort(int *array, int array_size){
    for (int i = 1; i < array_size; i++){
        int key = array[i];
        int j = i-1;
        while (j >= 0 && array[j] > key) {
            array[j+1] = array[j];
            j--;
        }
        array[j+1] = key;
        //-> invariant: array[0..j] is sorted
    }
};

//Performs a shell sort on an array of ints.
void ShellSort(int *array, int array_size){
    int h = 1;
    while (h < array_size) h = 3*h + 1;
    while (h > 0){
        h = h/3;
        for (int k = 0; k < h; k++){
            for (int i = h+k; i < array_size; i+=h){
                int key = array[i];
                int j = i-h;
                while (j>=0 && array[j] > key){
                    array[j+h] = array[j];
                    j-=h;
                }
                array[j+h] = key;
                //-> invariant: array[k,k+h...j] is sorted
            }
        }
        //->invariant: each h-sub-array is sorted
    }
};

//Performs a selection sort on an array of ints.
void SelectionSort(int *array, int array_size){
    for (int i = 0; i < array_size; i++){
        int iMin = i;

        for(int j = i+1; j < array_size; j++){
            if (array[iMin] > array[j]) iMin = j;
        }

        if (iMin != i){
            int tmp = array[i];
            array[i] = array[iMin];
            array[iMin] = tmp;
        }
        //->invariant: array[0...i] is sorted
    }
};

//Performs a heap sort on an array of ints.
void HeapSort(int *array, int array_size){

};

//Performs a merge sort on an array of ints.
void MergeSort(int *array, int array_size){

};

//Performs a quick sort on an array of ints.
void QuickSort(int *array, int array_size){
};<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// File contains modifications by: The Gulden developers
// All modifications:
// Copyright (c) 2016-2018 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@gmx.com)
// Distributed under the GULDEN software license, see the accompanying
// file COPYING

#if defined(HAVE_CONFIG_H)
#include "config/build-config.h"
#endif

#include "chainparamsbase.h"
#include "clientversion.h"
#include "fs.h"
#include "rpc/client.h"
#include "rpc/protocol.h"
#include "util.h"
#include "utilstrencodings.h"

#include <stdio.h>

#define _(x) std::string(x)/* Keep the _() around in case gettext or such will be used later to translate non-UI */
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>
#include "support/events.h"

#include <univalue.h>
#include "util.h"

static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
static const bool DEFAULT_NAMED=false;
static const int CONTINUE_EXECUTION=-1;

static std::string HelpMessageCli()
{
    const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
    const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
    std::string strUsage;
    strUsage += HelpMessageGroup(_("Options:"));
    strUsage += HelpMessageOpt("-?", _("This help message"));
    strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), DEFAULT_CONF_FILENAME));
    strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
    AppendParamsHelpMessages(strUsage);
    strUsage += HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED));
    strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
    strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));
    strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
    strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
    strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
    strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
    strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)"));

    return strUsage;
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//

//
// Exception thrown on connection error.  This error is used to determine
// when to wait if -rpcwait is given.
//
class CConnectionFailed : public std::runtime_error
{
public:

    explicit inline CConnectionFailed(const std::string& msg) :
        std::runtime_error(msg)
    {}

};

//
// This function returns either one of EXIT_ codes when it's expected to stop the process or
// CONTINUE_EXECUTION when it's expected to continue further.
//
static int AppInitRPC(int argc, char* argv[])
{
    //
    // Parameters
    //
    ParseParameters(argc, argv);
    if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version")) {
        std::string strUsage = strprintf(_("%s RPC client version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n";
        if (!IsArgSet("-version")) {
            strUsage += "\n" + _("Usage:") + "\n" +
                  "  "CLI_NAME" [options] <command> [params]  " + strprintf(_("Send command to %s"), _(PACKAGE_NAME)) + "\n" +
                  "  "CLI_NAME" [options] -named <command> [name=value] ... " + strprintf(_("Send command to %s (with named arguments)"), _(PACKAGE_NAME)) + "\n" +
                  "  "CLI_NAME" [options] help                " + _("List commands") + "\n" +
                  "  "CLI_NAME" [options] help <command>      " + _("Get help for a command") + "\n";

            strUsage += "\n" + HelpMessageCli();
        }

        fprintf(stdout, "%s", strUsage.c_str());
        if (argc < 2) {
            fprintf(stderr, "Error: too few parameters\n");
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
    }
    if (!fs::is_directory(GetDataDir(false))) {
        fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
        return EXIT_FAILURE;
    }
    try {
        ReadConfigFile(GetArg("-conf", DEFAULT_CONF_FILENAME));
    } catch (const std::exception& e) {
        fprintf(stderr,"Error reading configuration file: %s\n", e.what());
        return EXIT_FAILURE;
    }
    // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
    try {
        SelectBaseParams(ChainNameFromCommandLine());
    } catch (const std::exception& e) {
        fprintf(stderr, "Error: %s\n", e.what());
        return EXIT_FAILURE;
    }
    if (GetBoolArg("-rpcssl", false))
    {
        fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
        return EXIT_FAILURE;
    }
    return CONTINUE_EXECUTION;
}

/** Reply structure for request_done to fill in */
struct HTTPReply
{
    HTTPReply(): status(0), error(-1) {}

    int status;
    int error;
    std::string body;
};

const char *http_errorstring(int code)
{
    switch(code) {
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
    case EVREQ_HTTP_TIMEOUT:
        return "timeout reached";
    case EVREQ_HTTP_EOF:
        return "EOF reached";
    case EVREQ_HTTP_INVALID_HEADER:
        return "error while reading header, or invalid header";
    case EVREQ_HTTP_BUFFER_ERROR:
        return "error encountered while reading or writing";
    case EVREQ_HTTP_REQUEST_CANCEL:
        return "request was canceled";
    case EVREQ_HTTP_DATA_TOO_LONG:
        return "response body is larger than allowed";
#endif
    default:
        return "unknown";
    }
}

static void http_request_done(struct evhttp_request *req, void *ctx)
{
    HTTPReply *reply = static_cast<HTTPReply*>(ctx);

    if (req == NULL) {
        /* If req is NULL, it means an error occurred while connecting: the
         * error code will have been passed to http_error_cb.
         */
        reply->status = 0;
        return;
    }

    reply->status = evhttp_request_get_response_code(req);

    struct evbuffer *buf = evhttp_request_get_input_buffer(req);
    if (buf)
    {
        size_t size = evbuffer_get_length(buf);
        const char *data = (const char*)evbuffer_pullup(buf, size);
        if (data)
            reply->body = std::string(data, size);
        evbuffer_drain(buf, size);
    }
}

#if LIBEVENT_VERSION_NUMBER >= 0x02010300
static void http_error_cb(enum evhttp_request_error err, void *ctx)
{
    HTTPReply *reply = static_cast<HTTPReply*>(ctx);
    reply->error = err;
}
#endif

UniValue CallRPC(const std::string& strMethod, const UniValue& params)
{
    std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
    int port = GetArg("-rpcport", BaseParams().RPCPort());

    // Obtain event base
    raii_event_base base = obtain_event_base();

    // Synchronously look up hostname
    raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
    evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));

    HTTPReply response;
    raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
    if (req == NULL)
        throw std::runtime_error("create http request failed");
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
    evhttp_request_set_error_cb(req.get(), http_error_cb);
#endif

    // Get credentials
    std::string strRPCUserColonPass;
    if (GetArg("-rpcpassword", "") == "") {
        // Try fall back to cookie-based authentication if no password is provided
        if (!GetAuthCookie(&strRPCUserColonPass)) {
            throw std::runtime_error(strprintf(
                _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"),
                    GetConfigFile(GetArg("-conf", DEFAULT_CONF_FILENAME)).string().c_str()));

        }
    } else {
        strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");
    }

    struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
    assert(output_headers);
    evhttp_add_header(output_headers, "Host", host.c_str());
    evhttp_add_header(output_headers, "Connection", "close");
    evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());

    // Attach request data
    std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
    struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
    assert(output_buffer);
    evbuffer_add(output_buffer, strRequest.data(), strRequest.size());

    int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
    req.release(); // ownership moved to evcon in above call
    if (r != 0) {
        throw CConnectionFailed("send http request failed");
    }

    event_base_dispatch(base.get());

    if (response.status == 0)
        throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error));
    else if (response.status == HTTP_UNAUTHORIZED)
        throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
    else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
        throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
    else if (response.body.empty())
        throw std::runtime_error("no response from server");

    // Parse reply
    UniValue valReply(UniValue::VSTR);
    if (!valReply.read(response.body))
        throw std::runtime_error("couldn't parse reply from server");
    const UniValue& reply = valReply.get_obj();
    if (reply.empty())
        throw std::runtime_error("expected reply to have result, error and id properties");

    return reply;
}

int CommandLineRPC(int argc, char *argv[])
{
    std::string strPrint;
    int nRet = 0;
    try {
        // Skip switches
        while (argc > 1 && IsSwitchChar(argv[1][0])) {
            argc--;
            argv++;
        }
        std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
        if (GetBoolArg("-stdin", false)) {
            // Read one arg per line from stdin and append
            std::string line;
            while (std::getline(std::cin,line))
                args.push_back(line);
        }
        if (args.size() < 1)
            throw std::runtime_error("too few parameters (need at least command)");
        std::string strMethod = args[0];
        args.erase(args.begin()); // Remove trailing method name from arguments vector

        UniValue params;
        if(GetBoolArg("-named", DEFAULT_NAMED)) {
            params = RPCConvertNamedValues(strMethod, args);
        } else {
            params = RPCConvertValues(strMethod, args);
        }

        // Execute and handle connection failures with -rpcwait
        const bool fWait = GetBoolArg("-rpcwait", false);
        do {
            try {
                const UniValue reply = CallRPC(strMethod, params);

                // Parse reply
                const UniValue& result = find_value(reply, "result");
                const UniValue& error  = find_value(reply, "error");

                if (!error.isNull()) {
                    // Error
                    int code = error["code"].get_int();
                    if (fWait && code == RPC_IN_WARMUP)
                        throw CConnectionFailed("server in warmup");
                    strPrint = "error: " + error.write();
                    nRet = abs(code);
                    if (error.isObject())
                    {
                        UniValue errCode = find_value(error, "code");
                        UniValue errMsg  = find_value(error, "message");
                        strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";

                        if (errMsg.isStr())
                            strPrint += "error message:\n"+errMsg.get_str();
                    }
                } else {
                    // Result
                    if (result.isNull())
                        strPrint = "";
                    else if (result.isStr())
                        strPrint = result.get_str();
                    else
                        strPrint = result.write(2);
                }
                // Connection succeeded, no need to retry.
                break;
            }
            catch (const CConnectionFailed&) {
                if (fWait)
                    MilliSleep(1000);
                else
                    throw;
            }
        } while (fWait);
    }
    catch (const boost::thread_interrupted&) {
        throw;
    }
    catch (const std::exception& e) {
        strPrint = std::string("error: ") + e.what();
        nRet = EXIT_FAILURE;
    }
    catch (...) {
        PrintExceptionContinue(NULL, "CommandLineRPC()");
        throw;
    }

    if (strPrint != "") {
        fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
    }
    return nRet;
}

int main(int argc, char* argv[])
{
    SetupEnvironment();
    if (!SetupNetworking()) {
        fprintf(stderr, "Error: Initializing networking failed\n");
        return EXIT_FAILURE;
    }

    try {
        int ret = AppInitRPC(argc, argv);
        if (ret != CONTINUE_EXECUTION)
            return ret;
    }
    catch (const std::exception& e) {
        PrintExceptionContinue(&e, "AppInitRPC()");
        return EXIT_FAILURE;
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInitRPC()");
        return EXIT_FAILURE;
    }

    int ret = EXIT_FAILURE;
    try {
        ret = CommandLineRPC(argc, argv);
    }
    catch (const std::exception& e) {
        PrintExceptionContinue(&e, "CommandLineRPC()");
    } catch (...) {
        PrintExceptionContinue(NULL, "CommandLineRPC()");
    }
    return ret;
}

//fixme: (HIGH)
//Super gross workaround - for some reason our macos build keeps failing to provide '___cpu_model' symbol, so we just define it ourselves as a workaround until we can fix the issue.
#ifdef MAC_OSX
#include "llvm-cpumodel-hack.cpp"
#endif
<commit_msg>QA: Travis build fix<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// File contains modifications by: The Gulden developers
// All modifications:
// Copyright (c) 2016-2018 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@gmx.com)
// Distributed under the GULDEN software license, see the accompanying
// file COPYING

#if defined(HAVE_CONFIG_H)
#include "config/build-config.h"
#endif

#include "chainparamsbase.h"
#include "clientversion.h"
#include "fs.h"
#include "rpc/client.h"
#include "rpc/protocol.h"
#include "util.h"
#include "utilstrencodings.h"

#include <stdio.h>

#define _(x) std::string(x)/* Keep the _() around in case gettext or such will be used later to translate non-UI */
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>
#include "support/events.h"

#include <univalue.h>
#include "util.h"

static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
static const bool DEFAULT_NAMED=false;
static const int CONTINUE_EXECUTION=-1;

static std::string HelpMessageCli()
{
    const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
    const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET);
    std::string strUsage;
    strUsage += HelpMessageGroup(_("Options:"));
    strUsage += HelpMessageOpt("-?", _("This help message"));
    strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), DEFAULT_CONF_FILENAME));
    strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
    AppendParamsHelpMessages(strUsage);
    strUsage += HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED));
    strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
    strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort()));
    strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
    strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
    strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
    strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
    strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)"));

    return strUsage;
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//

//
// Exception thrown on connection error.  This error is used to determine
// when to wait if -rpcwait is given.
//
class CConnectionFailed : public std::runtime_error
{
public:

    explicit inline CConnectionFailed(const std::string& msg) :
        std::runtime_error(msg)
    {}

};

//
// This function returns either one of EXIT_ codes when it's expected to stop the process or
// CONTINUE_EXECUTION when it's expected to continue further.
//
static int AppInitRPC(int argc, char* argv[])
{
    //
    // Parameters
    //
    ParseParameters(argc, argv);
    if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version")) {
        std::string strUsage = strprintf(_("%s RPC client version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n";
        if (!IsArgSet("-version")) {
            strUsage += "\n" + _("Usage:") + "\n" +
                  "  " CLI_NAME " [options] <command> [params]  " + strprintf(_("Send command to %s"), _(PACKAGE_NAME)) + "\n" +
                  "  " CLI_NAME " [options] -named <command> [name=value] ... " + strprintf(_("Send command to %s (with named arguments)"), _(PACKAGE_NAME)) + "\n" +
                  "  " CLI_NAME " [options] help                " + _("List commands") + "\n" +
                  "  " CLI_NAME " [options] help <command>      " + _("Get help for a command") + "\n";

            strUsage += "\n" + HelpMessageCli();
        }

        fprintf(stdout, "%s", strUsage.c_str());
        if (argc < 2) {
            fprintf(stderr, "Error: too few parameters\n");
            return EXIT_FAILURE;
        }
        return EXIT_SUCCESS;
    }
    if (!fs::is_directory(GetDataDir(false))) {
        fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
        return EXIT_FAILURE;
    }
    try {
        ReadConfigFile(GetArg("-conf", DEFAULT_CONF_FILENAME));
    } catch (const std::exception& e) {
        fprintf(stderr,"Error reading configuration file: %s\n", e.what());
        return EXIT_FAILURE;
    }
    // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
    try {
        SelectBaseParams(ChainNameFromCommandLine());
    } catch (const std::exception& e) {
        fprintf(stderr, "Error: %s\n", e.what());
        return EXIT_FAILURE;
    }
    if (GetBoolArg("-rpcssl", false))
    {
        fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
        return EXIT_FAILURE;
    }
    return CONTINUE_EXECUTION;
}

/** Reply structure for request_done to fill in */
struct HTTPReply
{
    HTTPReply(): status(0), error(-1) {}

    int status;
    int error;
    std::string body;
};

const char *http_errorstring(int code)
{
    switch(code) {
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
    case EVREQ_HTTP_TIMEOUT:
        return "timeout reached";
    case EVREQ_HTTP_EOF:
        return "EOF reached";
    case EVREQ_HTTP_INVALID_HEADER:
        return "error while reading header, or invalid header";
    case EVREQ_HTTP_BUFFER_ERROR:
        return "error encountered while reading or writing";
    case EVREQ_HTTP_REQUEST_CANCEL:
        return "request was canceled";
    case EVREQ_HTTP_DATA_TOO_LONG:
        return "response body is larger than allowed";
#endif
    default:
        return "unknown";
    }
}

static void http_request_done(struct evhttp_request *req, void *ctx)
{
    HTTPReply *reply = static_cast<HTTPReply*>(ctx);

    if (req == NULL) {
        /* If req is NULL, it means an error occurred while connecting: the
         * error code will have been passed to http_error_cb.
         */
        reply->status = 0;
        return;
    }

    reply->status = evhttp_request_get_response_code(req);

    struct evbuffer *buf = evhttp_request_get_input_buffer(req);
    if (buf)
    {
        size_t size = evbuffer_get_length(buf);
        const char *data = (const char*)evbuffer_pullup(buf, size);
        if (data)
            reply->body = std::string(data, size);
        evbuffer_drain(buf, size);
    }
}

#if LIBEVENT_VERSION_NUMBER >= 0x02010300
static void http_error_cb(enum evhttp_request_error err, void *ctx)
{
    HTTPReply *reply = static_cast<HTTPReply*>(ctx);
    reply->error = err;
}
#endif

UniValue CallRPC(const std::string& strMethod, const UniValue& params)
{
    std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
    int port = GetArg("-rpcport", BaseParams().RPCPort());

    // Obtain event base
    raii_event_base base = obtain_event_base();

    // Synchronously look up hostname
    raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
    evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));

    HTTPReply response;
    raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
    if (req == NULL)
        throw std::runtime_error("create http request failed");
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
    evhttp_request_set_error_cb(req.get(), http_error_cb);
#endif

    // Get credentials
    std::string strRPCUserColonPass;
    if (GetArg("-rpcpassword", "") == "") {
        // Try fall back to cookie-based authentication if no password is provided
        if (!GetAuthCookie(&strRPCUserColonPass)) {
            throw std::runtime_error(strprintf(
                _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"),
                    GetConfigFile(GetArg("-conf", DEFAULT_CONF_FILENAME)).string().c_str()));

        }
    } else {
        strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");
    }

    struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
    assert(output_headers);
    evhttp_add_header(output_headers, "Host", host.c_str());
    evhttp_add_header(output_headers, "Connection", "close");
    evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());

    // Attach request data
    std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
    struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
    assert(output_buffer);
    evbuffer_add(output_buffer, strRequest.data(), strRequest.size());

    int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
    req.release(); // ownership moved to evcon in above call
    if (r != 0) {
        throw CConnectionFailed("send http request failed");
    }

    event_base_dispatch(base.get());

    if (response.status == 0)
        throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error));
    else if (response.status == HTTP_UNAUTHORIZED)
        throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
    else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
        throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
    else if (response.body.empty())
        throw std::runtime_error("no response from server");

    // Parse reply
    UniValue valReply(UniValue::VSTR);
    if (!valReply.read(response.body))
        throw std::runtime_error("couldn't parse reply from server");
    const UniValue& reply = valReply.get_obj();
    if (reply.empty())
        throw std::runtime_error("expected reply to have result, error and id properties");

    return reply;
}

int CommandLineRPC(int argc, char *argv[])
{
    std::string strPrint;
    int nRet = 0;
    try {
        // Skip switches
        while (argc > 1 && IsSwitchChar(argv[1][0])) {
            argc--;
            argv++;
        }
        std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
        if (GetBoolArg("-stdin", false)) {
            // Read one arg per line from stdin and append
            std::string line;
            while (std::getline(std::cin,line))
                args.push_back(line);
        }
        if (args.size() < 1)
            throw std::runtime_error("too few parameters (need at least command)");
        std::string strMethod = args[0];
        args.erase(args.begin()); // Remove trailing method name from arguments vector

        UniValue params;
        if(GetBoolArg("-named", DEFAULT_NAMED)) {
            params = RPCConvertNamedValues(strMethod, args);
        } else {
            params = RPCConvertValues(strMethod, args);
        }

        // Execute and handle connection failures with -rpcwait
        const bool fWait = GetBoolArg("-rpcwait", false);
        do {
            try {
                const UniValue reply = CallRPC(strMethod, params);

                // Parse reply
                const UniValue& result = find_value(reply, "result");
                const UniValue& error  = find_value(reply, "error");

                if (!error.isNull()) {
                    // Error
                    int code = error["code"].get_int();
                    if (fWait && code == RPC_IN_WARMUP)
                        throw CConnectionFailed("server in warmup");
                    strPrint = "error: " + error.write();
                    nRet = abs(code);
                    if (error.isObject())
                    {
                        UniValue errCode = find_value(error, "code");
                        UniValue errMsg  = find_value(error, "message");
                        strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";

                        if (errMsg.isStr())
                            strPrint += "error message:\n"+errMsg.get_str();
                    }
                } else {
                    // Result
                    if (result.isNull())
                        strPrint = "";
                    else if (result.isStr())
                        strPrint = result.get_str();
                    else
                        strPrint = result.write(2);
                }
                // Connection succeeded, no need to retry.
                break;
            }
            catch (const CConnectionFailed&) {
                if (fWait)
                    MilliSleep(1000);
                else
                    throw;
            }
        } while (fWait);
    }
    catch (const boost::thread_interrupted&) {
        throw;
    }
    catch (const std::exception& e) {
        strPrint = std::string("error: ") + e.what();
        nRet = EXIT_FAILURE;
    }
    catch (...) {
        PrintExceptionContinue(NULL, "CommandLineRPC()");
        throw;
    }

    if (strPrint != "") {
        fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
    }
    return nRet;
}

int main(int argc, char* argv[])
{
    SetupEnvironment();
    if (!SetupNetworking()) {
        fprintf(stderr, "Error: Initializing networking failed\n");
        return EXIT_FAILURE;
    }

    try {
        int ret = AppInitRPC(argc, argv);
        if (ret != CONTINUE_EXECUTION)
            return ret;
    }
    catch (const std::exception& e) {
        PrintExceptionContinue(&e, "AppInitRPC()");
        return EXIT_FAILURE;
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInitRPC()");
        return EXIT_FAILURE;
    }

    int ret = EXIT_FAILURE;
    try {
        ret = CommandLineRPC(argc, argv);
    }
    catch (const std::exception& e) {
        PrintExceptionContinue(&e, "CommandLineRPC()");
    } catch (...) {
        PrintExceptionContinue(NULL, "CommandLineRPC()");
    }
    return ret;
}

//fixme: (HIGH)
//Super gross workaround - for some reason our macos build keeps failing to provide '___cpu_model' symbol, so we just define it ourselves as a workaround until we can fix the issue.
#ifdef MAC_OSX
#include "llvm-cpumodel-hack.cpp"
#endif
<|endoftext|>


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

#ifndef VK_DEVICE_HPP_
#define VK_DEVICE_HPP_

#include "VkObject.hpp"
#include "Device/LRUCache.hpp"
#include "Reactor/Routine.hpp"
#include <memory>
#include <mutex>

namespace marl
{
	class Scheduler;
}

namespace sw
{
	class Blitter;
}

namespace vk
{

class PhysicalDevice;
class Queue;

class Device
{
public:
	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_DEVICE; }

	Device(const VkDeviceCreateInfo* pCreateInfo, void* mem, PhysicalDevice *physicalDevice, const VkPhysicalDeviceFeatures *enabledFeatures, const std::shared_ptr<marl::Scheduler>& scheduler);
	void destroy(const VkAllocationCallbacks* pAllocator);

	static size_t ComputeRequiredAllocationSize(const VkDeviceCreateInfo* pCreateInfo);

	bool hasExtension(const char* extensionName) const;
	VkQueue getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) const;
	VkResult waitForFences(uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout);
	VkResult waitIdle();
	void getDescriptorSetLayoutSupport(const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
	                                   VkDescriptorSetLayoutSupport* pSupport) const;
	PhysicalDevice *getPhysicalDevice() const { return physicalDevice; }
	void updateDescriptorSets(uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites,
	                          uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies);
	const VkPhysicalDeviceFeatures &getEnabledFeatures() const { return enabledFeatures; }
	sw::Blitter* getBlitter() const { return blitter.get(); }

	class SamplingRoutineCache
	{
	public:
		SamplingRoutineCache() : cache(1024) {}
		~SamplingRoutineCache() {}

		struct Key
		{
			uint32_t instruction;
			uint32_t sampler;
			uint32_t imageView;

			inline bool operator == (const Key& rhs) const;
			inline bool operator < (const Key& rhs) const;

			struct Hash
			{
				inline std::size_t operator()(const Key& key) const noexcept;
			};
		};

		std::shared_ptr<rr::Routine> query(const Key& key) const;
		void add(const Key& key, const std::shared_ptr<rr::Routine>& routine);

		rr::Routine* queryConst(const Key& key) const;
		void updateConstCache();

	private:
		sw::LRUConstCache<Key, std::shared_ptr<rr::Routine>, Key::Hash> cache;
	};

	SamplingRoutineCache* getSamplingRoutineCache() const;
	std::mutex& getSamplingRoutineCacheMutex();
	rr::Routine* findInConstCache(const SamplingRoutineCache::Key& key) const;
	void updateSamplingRoutineConstCache();

private:
	PhysicalDevice *const physicalDevice = nullptr;
	Queue *const queues = nullptr;
	uint32_t queueCount = 0;
	std::unique_ptr<sw::Blitter> blitter;
	std::unique_ptr<SamplingRoutineCache> samplingRoutineCache;
	std::mutex samplingRoutineCacheMutex;
	uint32_t enabledExtensionCount = 0;
	typedef char ExtensionName[VK_MAX_EXTENSION_NAME_SIZE];
	ExtensionName* extensions = nullptr;
	const VkPhysicalDeviceFeatures enabledFeatures = {};
	std::shared_ptr<marl::Scheduler> scheduler;
};

using DispatchableDevice = DispatchableObject<Device, VkDevice>;

static inline Device* Cast(VkDevice object)
{
	return DispatchableDevice::Cast(object);
}

inline bool vk::Device::SamplingRoutineCache::Key::operator == (const Key& rhs) const
{
	return instruction == rhs.instruction && sampler == rhs.sampler && imageView == rhs.imageView;
}

inline bool vk::Device::SamplingRoutineCache::Key::operator < (const Key& rhs) const
{
	return std::tie(instruction, sampler, imageView) < std::tie(rhs.instruction, rhs.sampler, rhs.imageView);
}

inline std::size_t vk::Device::SamplingRoutineCache::Key::Hash::operator() (const Key& key) const noexcept
{
	// Combine three 32-bit integers into a 64-bit hash.
	// 2642239 is the largest prime which when cubed is smaller than 2^64.
	uint64_t hash = key.instruction;
	hash = (hash * 2642239) ^ key.sampler;
	hash = (hash * 2642239) ^ key.imageView;
	return static_cast<std::size_t>(hash);  // Truncates to 32-bits on 32-bit platforms.
}

} // namespace vk

#endif // VK_DEVICE_HPP_
<commit_msg>Remove unused SamplingRoutineCache::Key::operator<<commit_after>// Copyright 2018 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef VK_DEVICE_HPP_
#define VK_DEVICE_HPP_

#include "VkObject.hpp"
#include "Device/LRUCache.hpp"
#include "Reactor/Routine.hpp"
#include <memory>
#include <mutex>

namespace marl
{
	class Scheduler;
}

namespace sw
{
	class Blitter;
}

namespace vk
{

class PhysicalDevice;
class Queue;

class Device
{
public:
	static constexpr VkSystemAllocationScope GetAllocationScope() { return VK_SYSTEM_ALLOCATION_SCOPE_DEVICE; }

	Device(const VkDeviceCreateInfo* pCreateInfo, void* mem, PhysicalDevice *physicalDevice, const VkPhysicalDeviceFeatures *enabledFeatures, const std::shared_ptr<marl::Scheduler>& scheduler);
	void destroy(const VkAllocationCallbacks* pAllocator);

	static size_t ComputeRequiredAllocationSize(const VkDeviceCreateInfo* pCreateInfo);

	bool hasExtension(const char* extensionName) const;
	VkQueue getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) const;
	VkResult waitForFences(uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout);
	VkResult waitIdle();
	void getDescriptorSetLayoutSupport(const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
	                                   VkDescriptorSetLayoutSupport* pSupport) const;
	PhysicalDevice *getPhysicalDevice() const { return physicalDevice; }
	void updateDescriptorSets(uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites,
	                          uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies);
	const VkPhysicalDeviceFeatures &getEnabledFeatures() const { return enabledFeatures; }
	sw::Blitter* getBlitter() const { return blitter.get(); }

	class SamplingRoutineCache
	{
	public:
		SamplingRoutineCache() : cache(1024) {}
		~SamplingRoutineCache() {}

		struct Key
		{
			uint32_t instruction;
			uint32_t sampler;
			uint32_t imageView;

			inline bool operator == (const Key& rhs) const;

			struct Hash
			{
				inline std::size_t operator()(const Key& key) const noexcept;
			};
		};

		std::shared_ptr<rr::Routine> query(const Key& key) const;
		void add(const Key& key, const std::shared_ptr<rr::Routine>& routine);

		rr::Routine* queryConst(const Key& key) const;
		void updateConstCache();

	private:
		sw::LRUConstCache<Key, std::shared_ptr<rr::Routine>, Key::Hash> cache;
	};

	SamplingRoutineCache* getSamplingRoutineCache() const;
	std::mutex& getSamplingRoutineCacheMutex();
	rr::Routine* findInConstCache(const SamplingRoutineCache::Key& key) const;
	void updateSamplingRoutineConstCache();

private:
	PhysicalDevice *const physicalDevice = nullptr;
	Queue *const queues = nullptr;
	uint32_t queueCount = 0;
	std::unique_ptr<sw::Blitter> blitter;
	std::unique_ptr<SamplingRoutineCache> samplingRoutineCache;
	std::mutex samplingRoutineCacheMutex;
	uint32_t enabledExtensionCount = 0;
	typedef char ExtensionName[VK_MAX_EXTENSION_NAME_SIZE];
	ExtensionName* extensions = nullptr;
	const VkPhysicalDeviceFeatures enabledFeatures = {};
	std::shared_ptr<marl::Scheduler> scheduler;
};

using DispatchableDevice = DispatchableObject<Device, VkDevice>;

static inline Device* Cast(VkDevice object)
{
	return DispatchableDevice::Cast(object);
}

inline bool vk::Device::SamplingRoutineCache::Key::operator == (const Key& rhs) const
{
	return instruction == rhs.instruction && sampler == rhs.sampler && imageView == rhs.imageView;
}

inline std::size_t vk::Device::SamplingRoutineCache::Key::Hash::operator() (const Key& key) const noexcept
{
	// Combine three 32-bit integers into a 64-bit hash.
	// 2642239 is the largest prime which when cubed is smaller than 2^64.
	uint64_t hash = key.instruction;
	hash = (hash * 2642239) ^ key.sampler;
	hash = (hash * 2642239) ^ key.imageView;
	return static_cast<std::size_t>(hash);  // Truncates to 32-bits on 32-bit platforms.
}

} // namespace vk

#endif // VK_DEVICE_HPP_
<|endoftext|>


<commit_before>#include <iostream>
#include <exception>
#include <fstream>
#include <sstream>
#include <regex>
#include "cli_utils.h"

// This file has utilities employed by the glnexus applet.
using namespace std;

namespace GLnexus {
namespace cli {
namespace utils {

// Parse a range like chr1:1000-2000. The item can also just be the name of a
// contig, in which case it gets mapped to the contig's full length.
bool parse_range(const vector<pair<string,size_t> >& contigs,
                 const string& range_txt, range& ans) {
    static regex re_range("([^:]+):([0-9,]+)-([0-9,]+)");

    string contig = range_txt;
    size_t beg=1, end=0;

    smatch sm;
    if (regex_match(range_txt, sm, re_range)) {
        assert(sm.size() == 4);
        contig = sm[1];
        string sbeg = sm[2], send = sm[3];
        sbeg.erase(std::remove(sbeg.begin(), sbeg.end(), ','), sbeg.end());
        send.erase(std::remove(send.begin(), send.end(), ','), send.end());
        beg = strtoul(sbeg.c_str(), nullptr, 10);
        end = strtoul(send.c_str(), nullptr, 10);
    }

    int rid=0;
    while (rid < contigs.size() && contig != contigs[rid].first) rid++;
    if (rid >= contigs.size()) {
        return false;
    }
    end = end>0 ? end : contigs[rid].second;
    if (beg < 1 || beg >= end) {
        return false;
    }
    ans = range(rid, beg-1, end);
    return true;
}

// parse a comma-separated list of ranges
bool parse_ranges(const vector<pair<string,size_t> >& contigs,
                  const string& ranges, vector<range>& ans) {
    ans.clear();

    string item;
    stringstream ss(ranges);
    while (std::getline(ss, item, ',')) {
        range range(-1,-1,-1);
        if (!parse_range(contigs, item, range)) {
            return false;
        }
        ans.push_back(range);
    }

    return true;
}

Status LoadYAMLFile(const string& filename, YAML::Node &node) {
    if (filename.size() == 0)
        return Status::Invalid("The YAML file must be specified");

    try {
        node = YAML::LoadFile(filename);
    } catch (exception &e) {
        return Status::Invalid("Error loading yaml file ", filename);
    }

    if (node.IsNull())
        return Status::NotFound("bad YAML file", filename);
    return Status::OK();
}

Status yaml_of_contigs(const std::vector<std::pair<std::string,size_t> > &contigs,
                       YAML::Emitter &yaml) {
    yaml << YAML::BeginSeq;
    for (const std::pair<string,size_t> &pr : contigs) {
        yaml << YAML::BeginMap;
        yaml << YAML::Key << "name";
        yaml << YAML::Value << pr.first;
        yaml << YAML::Key << "size";
        yaml << YAML::Value << pr.second;
        yaml << YAML::EndMap;
    }
    yaml << YAML::EndSeq;

    return Status::OK();
}

Status contigs_of_yaml(const YAML::Node& yaml,
                       std::vector<std::pair<std::string,size_t> > &contigs) {
    contigs.clear();

    // read contigs
    if (!yaml.IsSequence()) {
        return Status::Invalid("contigs should be a yaml sequence");
    }
    for (auto p = yaml.begin(); p != yaml.end(); ++p) {
        const std::string name = (*p)["name"].as<std::string>();
        size_t size = (*p)["size"].as<size_t>();
        contigs.push_back(make_pair(name, size));
    }

    return Status::OK();
}

// We write the stream as follows:
//
// ---
// contigs
// ---
// allele 1
// ---
// allele 2
// ---
// etc.
// allele N
// ...
//
// Each element is transformed to YAML, and then written to the output stream.
// This generates the document in pieces, while keeping it valid YAML.
Status yaml_stream_of_discovered_alleles(const std::vector<std::pair<std::string,size_t> > &contigs,
                                         const discovered_alleles &dsals,
                                         std::ostream &os) {
    Status s;

    // write the contigs
    {
        os << "---" << endl;
        YAML::Emitter yaml;
        S(yaml_of_contigs(contigs, yaml));
        os << yaml.c_str() << endl;
    }

    // Write alleles
    for (auto &pr : dsals) {
        os << "---" << endl;
        YAML::Emitter yaml;
        S(yaml_of_one_discovered_allele(pr.first, pr.second, contigs, yaml));
        os << yaml.c_str() << endl;
    }

    // special notation for end-of-file
    os << "..." << endl;

    return Status::OK();
}

static string yaml_begin_doc = "---";
static string yaml_end_doc_list = "...";

// Verify the document begins with '---' line. Move the stream position to the next line.
static Status yaml_verify_begin_doc_list(std::istream &is) {
    try {
        string marker;
        std::getline(is, marker);
        if (marker != yaml_begin_doc)
            return Status::Invalid("document does not start with `---`");
        return Status::OK();
    } catch (exception e) {
        string err = e.what();
        return Status::Failure("exception caught in yaml_verify_begin_doc_list: ", err);
    }
}

// Verify that we have reached the end of the file
static Status yaml_verify_eof(std::istream &is) {
    try {
        // The end-of-file flag is lit up only after reading past the
        // end of file
        char c;
        is.get(c);
        if (!is.eof()) {
            return Status::Invalid("Found YAML end-of-document marker, but there is unread data");
        }
        return Status::OK();
    } catch (exception e) {
        string err = e.what();
        return Status::Failure("exception caught in yaml_verify_eof: ", err);
    }
}

// In a YAML document built as a of document list, get the next document.
//
// Notes:
// -  Catch any exceptions, and convert to bad status
static Status yaml_get_next_document(std::istream &is,
                                     YAML::Node &ans,
                                     string& next_marker) {
    try {
        stringstream ss;

        while (is.good() && !is.eof()) {
            string line;
            std::getline(is, line);
            if (line.size() == 3) {
                // check if we reached the end of this top level document
                if (line == yaml_begin_doc ||
                    line == yaml_end_doc_list) {
                    // We have the entire document in memory. Convert to
                    // a YAML node and return.
                    next_marker = line;
                    ans = std::move(YAML::Load(ss.str()));
                    return Status::OK();
                }
            }
            ss.write(line.c_str(), line.size());
            ss.write("\n", 1);
        }

        if (!is.good())
            return Status::IOError("reading yaml stream");
        return Status::Invalid("premature end of document, did not find end-of-document marker");
    } catch (exception e) {
        string err = e.what();
        return Status::Failure("exception caught in yaml_get_next_document: ", err);
    }
}

Status discovered_alleles_of_yaml_stream(std::istream &is,
                                         std::vector<std::pair<std::string,size_t> > &contigs,
                                         discovered_alleles &dsals) {
    Status s;
    string next_marker;
    YAML::Node doc;

    contigs.clear();
    dsals.clear();
    S(yaml_verify_begin_doc_list(is));

    // The first top-level document is the contigs
    S(yaml_get_next_document(is, doc, next_marker));
    S(contigs_of_yaml(doc, contigs));

    // All other documents are discovered-alleles
    while (next_marker != yaml_end_doc_list) {
        S(yaml_get_next_document(is, doc, next_marker));

        allele allele(range(-1,-1,-1), "A");
        discovered_allele_info ainfo;

        S(one_discovered_allele_of_yaml(doc, contigs, allele, ainfo));
        dsals[allele] = ainfo;
    }
    S(yaml_verify_eof(is));

    if (contigs.size() == 0)
        return Status::Invalid("Empty contigs");
    return Status::OK();
}

// Serialize the unified sites to yaml format.
//
Status yaml_stream_of_unified_sites(const std::vector<unified_site> &sites,
                                    const std::vector<std::pair<std::string,size_t> > &contigs,
                                    std::ostream &os) {
    Status s;
    for (auto& u_site : sites) {
        os << "---" << endl;
        YAML::Emitter yaml;
        S(u_site.yaml(contigs, yaml));
        os << yaml.c_str() << endl;
    }

    // special notation for end-of-file
    os << "..." << endl;
    return Status::OK();
}

// Load the unified-sites from a file in yaml format.
//
Status unified_sites_of_yaml_stream(std::istream &is,
                                    const std::vector<std::pair<std::string,size_t> > &contigs,
                                    std::vector<unified_site> &sites) {
    Status s;
    string next_marker;
    sites.clear();

    S(yaml_verify_begin_doc_list(is));

    // Read a list of documents representing unified-sites
    do {
        YAML::Node doc;
        S(yaml_get_next_document(is, doc, next_marker));
        unified_site u_site(range(-1, -1, -1));
        S(unified_site::of_yaml(doc, contigs, u_site));
        sites.push_back(u_site);
    } while (next_marker != yaml_end_doc_list);

    S(yaml_verify_eof(is));
    return Status::OK();
}

// Load first file
Status merge_discovered_allele_files(std::shared_ptr<spdlog::logger> logger,
                                     const vector<string> &filenames,
                                     vector<pair<string,size_t>> &contigs,
                                     discovered_alleles &dsals) {
    Status s;
    if (filenames.size() == 0)
        return Status::Invalid("no discovered allele files provided");
    contigs.clear();
    dsals.clear();

    // Load the first file
    const string& first_file = filenames[0];
    {
        std::ifstream ifs(first_file.c_str());
        S(discovered_alleles_of_yaml_stream(ifs, contigs, dsals));
        logger->info() << "loaded " << dsals.size() << " alleles from " << first_file;
        ifs.close();
    }

    if (filenames.size() == 1)
        return Status::OK();

    // Load the rest of the files, and merge
    for (auto it = filenames.begin() + 1; it != filenames.end(); ++it) {
        vector<pair<string,size_t>> contigs2;
        discovered_alleles dsals2;
        const string &crnt_file = *it;
        std::ifstream ifs(crnt_file.c_str());

        S(discovered_alleles_of_yaml_stream(ifs, contigs2, dsals2));
        logger->info() << "loaded " << dsals2.size() << " alleles from " << crnt_file;
        ifs.close();

        // verify that the contigs are the same
        if (contigs != contigs2) {
            return Status::Invalid("The contigs are different between", first_file + " " + crnt_file);
        }

        S(merge_discovered_alleles(dsals2, dsals));
    }

    return Status::OK();
}

Status find_containing_range(const std::set<range> &ranges,
                             const range &pos,
                             range &ans) {
    if (ranges.size() == 0) {
        return Status::NotFound();
    }

    // The returned value here is the first element that is
    // greater or equal to [pos].
    auto it = ranges.lower_bound(pos);
    if (it == ranges.end() ||  !it->contains(pos)) {
        // we landed one range after the one we need
        if (it != ranges.begin()) {
            it = std::prev(it);
        }
    }

    if (it->contains(pos)) {
        // we got the right range
        ans = *it;
        return Status::OK();
    }
    return Status::NotFound();
}

}}}
<commit_msg>cli_utils::discovered_alleles_of_yaml_stream: deallocate YAML::Node every time<commit_after>#include <iostream>
#include <exception>
#include <fstream>
#include <sstream>
#include <regex>
#include "cli_utils.h"

// This file has utilities employed by the glnexus applet.
using namespace std;

namespace GLnexus {
namespace cli {
namespace utils {

// Parse a range like chr1:1000-2000. The item can also just be the name of a
// contig, in which case it gets mapped to the contig's full length.
bool parse_range(const vector<pair<string,size_t> >& contigs,
                 const string& range_txt, range& ans) {
    static regex re_range("([^:]+):([0-9,]+)-([0-9,]+)");

    string contig = range_txt;
    size_t beg=1, end=0;

    smatch sm;
    if (regex_match(range_txt, sm, re_range)) {
        assert(sm.size() == 4);
        contig = sm[1];
        string sbeg = sm[2], send = sm[3];
        sbeg.erase(std::remove(sbeg.begin(), sbeg.end(), ','), sbeg.end());
        send.erase(std::remove(send.begin(), send.end(), ','), send.end());
        beg = strtoul(sbeg.c_str(), nullptr, 10);
        end = strtoul(send.c_str(), nullptr, 10);
    }

    int rid=0;
    while (rid < contigs.size() && contig != contigs[rid].first) rid++;
    if (rid >= contigs.size()) {
        return false;
    }
    end = end>0 ? end : contigs[rid].second;
    if (beg < 1 || beg >= end) {
        return false;
    }
    ans = range(rid, beg-1, end);
    return true;
}

// parse a comma-separated list of ranges
bool parse_ranges(const vector<pair<string,size_t> >& contigs,
                  const string& ranges, vector<range>& ans) {
    ans.clear();

    string item;
    stringstream ss(ranges);
    while (std::getline(ss, item, ',')) {
        range range(-1,-1,-1);
        if (!parse_range(contigs, item, range)) {
            return false;
        }
        ans.push_back(range);
    }

    return true;
}

Status LoadYAMLFile(const string& filename, YAML::Node &node) {
    if (filename.size() == 0)
        return Status::Invalid("The YAML file must be specified");

    try {
        node = YAML::LoadFile(filename);
    } catch (exception &e) {
        return Status::Invalid("Error loading yaml file ", filename);
    }

    if (node.IsNull())
        return Status::NotFound("bad YAML file", filename);
    return Status::OK();
}

Status yaml_of_contigs(const std::vector<std::pair<std::string,size_t> > &contigs,
                       YAML::Emitter &yaml) {
    yaml << YAML::BeginSeq;
    for (const std::pair<string,size_t> &pr : contigs) {
        yaml << YAML::BeginMap;
        yaml << YAML::Key << "name";
        yaml << YAML::Value << pr.first;
        yaml << YAML::Key << "size";
        yaml << YAML::Value << pr.second;
        yaml << YAML::EndMap;
    }
    yaml << YAML::EndSeq;

    return Status::OK();
}

Status contigs_of_yaml(const YAML::Node& yaml,
                       std::vector<std::pair<std::string,size_t> > &contigs) {
    contigs.clear();

    // read contigs
    if (!yaml.IsSequence()) {
        return Status::Invalid("contigs should be a yaml sequence");
    }
    for (auto p = yaml.begin(); p != yaml.end(); ++p) {
        const std::string name = (*p)["name"].as<std::string>();
        size_t size = (*p)["size"].as<size_t>();
        contigs.push_back(make_pair(name, size));
    }

    return Status::OK();
}

// We write the stream as follows:
//
// ---
// contigs
// ---
// allele 1
// ---
// allele 2
// ---
// etc.
// allele N
// ...
//
// Each element is transformed to YAML, and then written to the output stream.
// This generates the document in pieces, while keeping it valid YAML.
Status yaml_stream_of_discovered_alleles(const std::vector<std::pair<std::string,size_t> > &contigs,
                                         const discovered_alleles &dsals,
                                         std::ostream &os) {
    Status s;

    // write the contigs
    {
        os << "---" << endl;
        YAML::Emitter yaml;
        S(yaml_of_contigs(contigs, yaml));
        os << yaml.c_str() << endl;
    }

    // Write alleles
    for (auto &pr : dsals) {
        os << "---" << endl;
        YAML::Emitter yaml;
        S(yaml_of_one_discovered_allele(pr.first, pr.second, contigs, yaml));
        os << yaml.c_str() << endl;
    }

    // special notation for end-of-file
    os << "..." << endl;

    return Status::OK();
}

static string yaml_begin_doc = "---";
static string yaml_end_doc_list = "...";

// Verify the document begins with '---' line. Move the stream position to the next line.
static Status yaml_verify_begin_doc_list(std::istream &is) {
    try {
        string marker;
        std::getline(is, marker);
        if (marker != yaml_begin_doc)
            return Status::Invalid("document does not start with `---`");
        return Status::OK();
    } catch (exception e) {
        string err = e.what();
        return Status::Failure("exception caught in yaml_verify_begin_doc_list: ", err);
    }
}

// Verify that we have reached the end of the file
static Status yaml_verify_eof(std::istream &is) {
    try {
        // The end-of-file flag is lit up only after reading past the
        // end of file
        char c;
        is.get(c);
        if (!is.eof()) {
            return Status::Invalid("Found YAML end-of-document marker, but there is unread data");
        }
        return Status::OK();
    } catch (exception e) {
        string err = e.what();
        return Status::Failure("exception caught in yaml_verify_eof: ", err);
    }
}

// In a YAML document built as a of document list, get the next document.
//
// Notes:
// -  Catch any exceptions, and convert to bad status
static Status yaml_get_next_document(std::istream &is,
                                     YAML::Node &ans,
                                     string& next_marker) {
    try {
        stringstream ss;

        while (is.good() && !is.eof()) {
            string line;
            std::getline(is, line);
            if (line.size() == 3) {
                // check if we reached the end of this top level document
                if (line == yaml_begin_doc ||
                    line == yaml_end_doc_list) {
                    // We have the entire document in memory. Convert to
                    // a YAML node and return.
                    next_marker = line;
                    ans = std::move(YAML::Load(ss.str()));
                    return Status::OK();
                }
            }
            ss.write(line.c_str(), line.size());
            ss.write("\n", 1);
        }

        if (!is.good())
            return Status::IOError("reading yaml stream");
        return Status::Invalid("premature end of document, did not find end-of-document marker");
    } catch (exception e) {
        string err = e.what();
        return Status::Failure("exception caught in yaml_get_next_document: ", err);
    }
}

Status discovered_alleles_of_yaml_stream(std::istream &is,
                                         std::vector<std::pair<std::string,size_t> > &contigs,
                                         discovered_alleles &dsals) {
    Status s;
    string next_marker;

    contigs.clear();
    dsals.clear();
    S(yaml_verify_begin_doc_list(is));

    // The first top-level document is the contigs
    {
        YAML::Node doc;
        S(yaml_get_next_document(is, doc, next_marker));
        S(contigs_of_yaml(doc, contigs));
    }

    // All other documents are discovered-alleles
    while (next_marker != yaml_end_doc_list) {
        YAML::Node doc;
        S(yaml_get_next_document(is, doc, next_marker));

        allele allele(range(-1,-1,-1), "A");
        discovered_allele_info ainfo;

        S(one_discovered_allele_of_yaml(doc, contigs, allele, ainfo));
        dsals[allele] = ainfo;
    }
    S(yaml_verify_eof(is));

    if (contigs.size() == 0)
        return Status::Invalid("Empty contigs");
    return Status::OK();
}

// Serialize the unified sites to yaml format.
//
Status yaml_stream_of_unified_sites(const std::vector<unified_site> &sites,
                                    const std::vector<std::pair<std::string,size_t> > &contigs,
                                    std::ostream &os) {
    Status s;
    for (auto& u_site : sites) {
        os << "---" << endl;
        YAML::Emitter yaml;
        S(u_site.yaml(contigs, yaml));
        os << yaml.c_str() << endl;
    }

    // special notation for end-of-file
    os << "..." << endl;
    return Status::OK();
}

// Load the unified-sites from a file in yaml format.
//
Status unified_sites_of_yaml_stream(std::istream &is,
                                    const std::vector<std::pair<std::string,size_t> > &contigs,
                                    std::vector<unified_site> &sites) {
    Status s;
    string next_marker;
    sites.clear();

    S(yaml_verify_begin_doc_list(is));

    // Read a list of documents representing unified-sites
    do {
        YAML::Node doc;
        S(yaml_get_next_document(is, doc, next_marker));
        unified_site u_site(range(-1, -1, -1));
        S(unified_site::of_yaml(doc, contigs, u_site));
        sites.push_back(u_site);
    } while (next_marker != yaml_end_doc_list);

    S(yaml_verify_eof(is));
    return Status::OK();
}

// Load first file
Status merge_discovered_allele_files(std::shared_ptr<spdlog::logger> logger,
                                     const vector<string> &filenames,
                                     vector<pair<string,size_t>> &contigs,
                                     discovered_alleles &dsals) {
    Status s;
    if (filenames.size() == 0)
        return Status::Invalid("no discovered allele files provided");
    contigs.clear();
    dsals.clear();

    // Load the first file
    const string& first_file = filenames[0];
    {
        std::ifstream ifs(first_file.c_str());
        S(discovered_alleles_of_yaml_stream(ifs, contigs, dsals));
        logger->info() << "loaded " << dsals.size() << " alleles from " << first_file;
        ifs.close();
    }

    if (filenames.size() == 1)
        return Status::OK();

    // Load the rest of the files, and merge
    for (auto it = filenames.begin() + 1; it != filenames.end(); ++it) {
        vector<pair<string,size_t>> contigs2;
        discovered_alleles dsals2;
        const string &crnt_file = *it;
        std::ifstream ifs(crnt_file.c_str());

        S(discovered_alleles_of_yaml_stream(ifs, contigs2, dsals2));
        logger->info() << "loaded " << dsals2.size() << " alleles from " << crnt_file;
        ifs.close();

        // verify that the contigs are the same
        if (contigs != contigs2) {
            return Status::Invalid("The contigs are different between", first_file + " " + crnt_file);
        }

        S(merge_discovered_alleles(dsals2, dsals));
    }

    return Status::OK();
}

Status find_containing_range(const std::set<range> &ranges,
                             const range &pos,
                             range &ans) {
    if (ranges.size() == 0) {
        return Status::NotFound();
    }

    // The returned value here is the first element that is
    // greater or equal to [pos].
    auto it = ranges.lower_bound(pos);
    if (it == ranges.end() ||  !it->contains(pos)) {
        // we landed one range after the one we need
        if (it != ranges.begin()) {
            it = std::prev(it);
        }
    }

    if (it->contains(pos)) {
        // we got the right range
        ans = *it;
        return Status::OK();
    }
    return Status::NotFound();
}

}}}
<|endoftext|>