<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \class QAnimationGroup
    \brief The QAnimationGroup is an abstract base class for group of animations.
    \since 4.5
    \ingroup animation
    \preliminary

    QAnimationGroup represents a group of animations, such as parallel or sequential,
    and lets you combine different animations into one. The group manages any animation
    that inherits QAbstractAnimation. By combining groups, you can easily construct
    complex animation graphs.

    The QAnimationGroup base class provides methods for adding and retrieving animations.
    Besides that, you can remove animations by calling remove(), and clear the animation
    group by calling clearAnimations(). You may keep track of changes in the group's animations by
    listening to QEvent::ChildAdded and QEvent::ChildRemoved events.

    QAnimationGroup takes ownership of the animations it manages, and ensures that they are
    deleted when the animation group is deleted.

    \sa QAbstractAnimation, QVariantAnimation, {The Animation Framework}
*/

#ifndef QT_NO_ANIMATION

#include "qanimationgroup.h"
#include <QtCore/qdebug.h>
#include <QtCore/qcoreevent.h>
#include "qanimationgroup_p.h"

QT_BEGIN_NAMESPACE

/*!
    Constructs a QAnimationGroup.
    \a parent is passed to QObject's constructor.
*/
QAnimationGroup::QAnimationGroup(QObject *parent)
    : QAbstractAnimation(*new QAnimationGroupPrivate, parent)
{
}

/*!
    \internal
*/
QAnimationGroup::QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent)
    : QAbstractAnimation(dd, parent)
{
}

/*!
    Destroys the animation group. It will also destroy all its animations.
*/
QAnimationGroup::~QAnimationGroup()
{
}

/*!
    Returns a pointer to the animation at \a index in this group. This
    function is useful when you need access to a particular animation.  \a
    index is between 0 and animationCount() - 1.

    \sa animationCount(), indexOfAnimation()
*/
QAbstractAnimation *QAnimationGroup::animationAt(int index) const
{
    Q_D(const QAnimationGroup);

    if (index < 0 || index >= d->animations.size()) {
        qWarning("QAnimationGroup::animationAt: index is out of bounds");
        return 0;
    }

    return d->animations.at(index);
}

/*!
    Returns the number of animations managed by this group.

    \sa indexOfAnimation(), addAnimation(), animationAt()
*/
int QAnimationGroup::animationCount() const
{
    Q_D(const QAnimationGroup);
    return d->animations.size();
}

/*!
    Returns the index of \a animation. The returned index can be passed
    to the other functions that take an index as an argument.

    \sa insertAnimationAt() animationAt(), takeAnimationAt()
*/
int QAnimationGroup::indexOfAnimation(QAbstractAnimation *animation) const
{
    Q_D(const QAnimationGroup);
    return d->animations.indexOf(animation);
}

/*!
    Adds \a animation to this group. This will call insertAnimationAt with
    index equals to animationCount()
*/
void QAnimationGroup::addAnimation(QAbstractAnimation *animation)
{
    Q_D(QAnimationGroup);
    insertAnimationAt(d->animations.count(), animation);
}

/*!
    Inserts \a animation into this animation group at \a index.
    If \a index is 0 the animation is inserted at the beginning.
    If \a index is animationCount(), the animation is inserted at the end.
    \sa takeAnimationAt(), addAnimation(), indexOfAnimation()
*/
void QAnimationGroup::insertAnimationAt(int index, QAbstractAnimation *animation)
{
    Q_D(QAnimationGroup);

    if (index < 0 || index > d->animations.size()) {
        qWarning("QAnimationGroup::insertAnimationAt: index is out of bounds");
        return;
    }

    if (QAnimationGroup *oldGroup = animation->group())
        oldGroup->removeAnimation(animation);

    d->animations.insert(index, animation);
    QAbstractAnimationPrivate::get(animation)->group = this;
    // this will make sure that ChildAdded event is sent to 'this'
    animation->setParent(this);
    d->animationInsertedAt(index);
}

/*!
    Removes \a animation from this group. The ownership of \a animation is
    transferred to the caller.

    \sa takeAnimationAt(), insertAnimationAt(), addAnimation()
*/
void QAnimationGroup::removeAnimation(QAbstractAnimation *animation)
{
    Q_D(QAnimationGroup);

    if (!animation) {
        qWarning("QAnimationGroup::remove: cannot remove null animation");
        return;
    }
    int index = d->animations.indexOf(animation);
    if (index == -1) {
        qWarning("QAnimationGroup::remove: animation is not part of this group");
        return;
    }

    takeAnimationAt(index);
}

/*!
    Removes the animation at \a index from this animation group. The ownership
    of the animation is transferred to the caller, and a pointer to the removed
    animation is returned.

    \sa addAnimation()
*/
QAbstractAnimation *QAnimationGroup::takeAnimationAt(int index)
{
    Q_D(QAnimationGroup);
    if (index < 0 || index >= d->animations.size()) {
        qWarning("QAnimationGroup::takeAnimationAt: no animation at index %d", index);
        return 0;
    }
    QAbstractAnimation *animation = d->animations.at(index);
    QAbstractAnimationPrivate::get(animation)->group = 0;
    // ### removing from list before doing setParent to avoid inifinite recursion
    // in ChildRemoved event
    d->animations.removeAt(index);
    animation->setParent(0);
    d->animationRemovedAt(index);
    return animation;
}

/*!
    Removes and deletes all animations in this animation group, and resets the current
    time to 0.

    \sa addAnimation(), removeAnimation()
*/
void QAnimationGroup::clearAnimations()
{
    Q_D(QAnimationGroup);
    qDeleteAll(d->animations);
}

/*!
    \reimp
*/
bool QAnimationGroup::event(QEvent *event)
{
    Q_D(QAnimationGroup);
    if (event->type() == QEvent::ChildAdded) {
        QChildEvent *childEvent = static_cast<QChildEvent *>(event);
        if (QAbstractAnimation *a = qobject_cast<QAbstractAnimation *>(childEvent->child())) {
            if (a->group() != this)
                addAnimation(a);
        }
    } else if (event->type() == QEvent::ChildRemoved) {
        QChildEvent *childEvent = static_cast<QChildEvent *>(event);
        QAbstractAnimation *a = static_cast<QAbstractAnimation *>(childEvent->child());
        // You can only rely on the child being a QObject because in the QEvent::ChildRemoved
        // case it might be called from the destructor.
        int index = d->animations.indexOf(a);
        if (index != -1)
            takeAnimationAt(index);
    }
    return QAbstractAnimation::event(event);
}

void QAnimationGroupPrivate::animationRemovedAt(int index)
{
    Q_Q(QAnimationGroup);
    Q_UNUSED(index);
    if (animations.isEmpty()) {
        currentTime = 0;
        q->stop();
    }
}

QT_END_NAMESPACE

#include "moc_qanimationgroup.cpp"

#endif //QT_NO_ANIMATION
<commit_msg>Doc: Work on QAnimationGroup class description.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \class QAnimationGroup
    \brief The QAnimationGroup is an abstract base class for group of animations.
    \since 4.5
    \ingroup animation
    \preliminary

    An animation group is a container for animations (subclasses of
    QAbstractAnimation). A group is usually responsible for managing
    the \l{QAbstractAnimation::State}{state} of its animations, i.e.,
    it decides when to start, stop, resume, and pause them. Currently,
    Qt provides two such groups: QParallelAnimationGroup and
    QSequentialAnimationGroup. Look up their class descriptions for
    details.

    Since QAnimationGroup inherits from QAbstractAnimation, you can
    combine groups, and easily construct complex animation graphs.
    You can query QAbstractAnimation for the group it belongs to
    (using the \l{QAbstractAnimation::}{group()} function).

    To start a top-level animation group, you simply use the
    \l{QAbstractAnimation::}{start()} function from
    QAbstractAnimation. By a top-level animation group, we think of a
    group that itself is not contained within another group. Starting
    sub groups directly is not supported, and may lead to unexpected
    behavior.

    \omit OK, we'll put in a snippet on this here \endomit

    QAnimationGroup provides methods for adding and retrieving
    animations. Besides that, you can remove animations by calling
    remove(), and clear the animation group by calling
    clearAnimations(). You may keep track of changes in the group's
    animations by listening to QEvent::ChildAdded and
    QEvent::ChildRemoved events.

    \omit OK, let's find a snippet here as well. \endomit

    QAnimationGroup takes ownership of the animations it manages, and
    ensures that they are deleted when the animation group is deleted.

    You can also use a \l{The State Machine Framework}{state machine}
    to create complex animations. The framework provides a special
    state, QAnimationState, that plays an animation upon entry and
    transitions to a new state when the animation has finished
    playing. This technique can also be combined with using animation
    groups.

    \sa QAbstractAnimation, QVariantAnimation, {The Animation Framework}
*/

#ifndef QT_NO_ANIMATION

#include "qanimationgroup.h"
#include <QtCore/qdebug.h>
#include <QtCore/qcoreevent.h>
#include "qanimationgroup_p.h"

QT_BEGIN_NAMESPACE

/*!
    Constructs a QAnimationGroup.
    \a parent is passed to QObject's constructor.
*/
QAnimationGroup::QAnimationGroup(QObject *parent)
    : QAbstractAnimation(*new QAnimationGroupPrivate, parent)
{
}

/*!
    \internal
*/
QAnimationGroup::QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent)
    : QAbstractAnimation(dd, parent)
{
}

/*!
    Destroys the animation group. It will also destroy all its animations.
*/
QAnimationGroup::~QAnimationGroup()
{
}

/*!
    Returns a pointer to the animation at \a index in this group. This
    function is useful when you need access to a particular animation.  \a
    index is between 0 and animationCount() - 1.

    \sa animationCount(), indexOfAnimation()
*/
QAbstractAnimation *QAnimationGroup::animationAt(int index) const
{
    Q_D(const QAnimationGroup);

    if (index < 0 || index >= d->animations.size()) {
        qWarning("QAnimationGroup::animationAt: index is out of bounds");
        return 0;
    }

    return d->animations.at(index);
}

/*!
    Returns the number of animations managed by this group.

    \sa indexOfAnimation(), addAnimation(), animationAt()
*/
int QAnimationGroup::animationCount() const
{
    Q_D(const QAnimationGroup);
    return d->animations.size();
}

/*!
    Returns the index of \a animation. The returned index can be passed
    to the other functions that take an index as an argument.

    \sa insertAnimationAt() animationAt(), takeAnimationAt()
*/
int QAnimationGroup::indexOfAnimation(QAbstractAnimation *animation) const
{
    Q_D(const QAnimationGroup);
    return d->animations.indexOf(animation);
}

/*!
    Adds \a animation to this group. This will call insertAnimationAt with
    index equals to animationCount()
*/
void QAnimationGroup::addAnimation(QAbstractAnimation *animation)
{
    Q_D(QAnimationGroup);
    insertAnimationAt(d->animations.count(), animation);
}

/*!
    Inserts \a animation into this animation group at \a index.
    If \a index is 0 the animation is inserted at the beginning.
    If \a index is animationCount(), the animation is inserted at the end.
    \sa takeAnimationAt(), addAnimation(), indexOfAnimation()
*/
void QAnimationGroup::insertAnimationAt(int index, QAbstractAnimation *animation)
{
    Q_D(QAnimationGroup);

    if (index < 0 || index > d->animations.size()) {
        qWarning("QAnimationGroup::insertAnimationAt: index is out of bounds");
        return;
    }

    if (QAnimationGroup *oldGroup = animation->group())
        oldGroup->removeAnimation(animation);

    d->animations.insert(index, animation);
    QAbstractAnimationPrivate::get(animation)->group = this;
    // this will make sure that ChildAdded event is sent to 'this'
    animation->setParent(this);
    d->animationInsertedAt(index);
}

/*!
    Removes \a animation from this group. The ownership of \a animation is
    transferred to the caller.

    \sa takeAnimationAt(), insertAnimationAt(), addAnimation()
*/
void QAnimationGroup::removeAnimation(QAbstractAnimation *animation)
{
    Q_D(QAnimationGroup);

    if (!animation) {
        qWarning("QAnimationGroup::remove: cannot remove null animation");
        return;
    }
    int index = d->animations.indexOf(animation);
    if (index == -1) {
        qWarning("QAnimationGroup::remove: animation is not part of this group");
        return;
    }

    takeAnimationAt(index);
}

/*!
    Removes the animation at \a index from this animation group. The ownership
    of the animation is transferred to the caller, and a pointer to the removed
    animation is returned.

    \sa addAnimation()
*/
QAbstractAnimation *QAnimationGroup::takeAnimationAt(int index)
{
    Q_D(QAnimationGroup);
    if (index < 0 || index >= d->animations.size()) {
        qWarning("QAnimationGroup::takeAnimationAt: no animation at index %d", index);
        return 0;
    }
    QAbstractAnimation *animation = d->animations.at(index);
    QAbstractAnimationPrivate::get(animation)->group = 0;
    // ### removing from list before doing setParent to avoid inifinite recursion
    // in ChildRemoved event
    d->animations.removeAt(index);
    animation->setParent(0);
    d->animationRemovedAt(index);
    return animation;
}

/*!
    Removes and deletes all animations in this animation group, and resets the current
    time to 0.

    \sa addAnimation(), removeAnimation()
*/
void QAnimationGroup::clearAnimations()
{
    Q_D(QAnimationGroup);
    qDeleteAll(d->animations);
}

/*!
    \reimp
*/
bool QAnimationGroup::event(QEvent *event)
{
    Q_D(QAnimationGroup);
    if (event->type() == QEvent::ChildAdded) {
        QChildEvent *childEvent = static_cast<QChildEvent *>(event);
        if (QAbstractAnimation *a = qobject_cast<QAbstractAnimation *>(childEvent->child())) {
            if (a->group() != this)
                addAnimation(a);
        }
    } else if (event->type() == QEvent::ChildRemoved) {
        QChildEvent *childEvent = static_cast<QChildEvent *>(event);
        QAbstractAnimation *a = static_cast<QAbstractAnimation *>(childEvent->child());
        // You can only rely on the child being a QObject because in the QEvent::ChildRemoved
        // case it might be called from the destructor.
        int index = d->animations.indexOf(a);
        if (index != -1)
            takeAnimationAt(index);
    }
    return QAbstractAnimation::event(event);
}

void QAnimationGroupPrivate::animationRemovedAt(int index)
{
    Q_Q(QAnimationGroup);
    Q_UNUSED(index);
    if (animations.isEmpty()) {
        currentTime = 0;
        q->stop();
    }
}

QT_END_NAMESPACE

#include "moc_qanimationgroup.cpp"

#endif //QT_NO_ANIMATION
<|endoftext|>


<commit_before>#ifndef SILICIUM_ITERATOR_RANGE_HPP
#define SILICIUM_ITERATOR_RANGE_HPP

#include <silicium/config.hpp>
#include <boost/static_assert.hpp>
#include <cassert>

namespace Si
{
	namespace detail
	{
		//std::iterator_traits<T const *>::value_type seems to be T (GCC 4.8), but that
		//is not useful at all because the const is missing.
		template <class Iterator>
		struct actual_value_type
		{
			typedef typename std::remove_reference<decltype(*std::declval<Iterator>())>::type type;
		};
	}

	template <class Iterator>
	struct iterator_range
	{
		typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
		typedef typename detail::actual_value_type<Iterator>::type value_type;
		typedef Iterator iterator;
		typedef Iterator const_iterator;

		BOOST_CONSTEXPR iterator_range() BOOST_NOEXCEPT
			: m_begin(Iterator())
			, m_end(Iterator())
		{
		}

		template <class It1, class It2>
		BOOST_CONSTEXPR iterator_range(It1 &&begin, It2 &&end) BOOST_NOEXCEPT
			: m_begin(std::forward<It1>(begin))
			, m_end(std::forward<It2>(end))
		{
		}

		template <class OtherIterator>
		iterator_range(iterator_range<OtherIterator> const &other) BOOST_NOEXCEPT
			: m_begin(other.begin())
			, m_end(other.end())
		{
		}

		BOOST_CONSTEXPR Iterator const &begin() const BOOST_NOEXCEPT
		{
			return m_begin;
		}

		BOOST_CONSTEXPR Iterator const &end() const BOOST_NOEXCEPT
		{
			return m_end;
		}

		BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT
		{
			return m_begin == m_end;
		}

		BOOST_CONSTEXPR difference_type size() const BOOST_NOEXCEPT
		{
			return std::distance(m_begin, m_end);
		}

		SILICIUM_CXX14_CONSTEXPR void pop_front(difference_type n) BOOST_NOEXCEPT
		{
			assert(n <= size());
			std::advance(m_begin, n);
		}

		SILICIUM_CXX14_CONSTEXPR void pop_front() BOOST_NOEXCEPT
		{
			assert(!empty());
			pop_front(1);
		}

		value_type &front() const BOOST_NOEXCEPT
		{
			assert(!empty());
			return (*this)[0];
		}

		value_type &operator[](difference_type index) const BOOST_NOEXCEPT
		{
			assert(index < size());
			return begin()[index];
		}

	private:

		Iterator m_begin, m_end;
	};

	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &begin(iterator_range<Iterator> const &range)
	{
		return range.begin();
	}

	//for Boost.Range compatibility
	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &range_begin(iterator_range<Iterator> const &range)
	{
		return range.begin();
	}

	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &end(iterator_range<Iterator> const &range)
	{
		return range.end();
	}

	template <class Iterator1, class Iterator2>
	BOOST_CONSTEXPR auto make_iterator_range(Iterator1 &&begin, Iterator2 &&end)
#if !SILICIUM_COMPILER_HAS_AUTO_RETURN_TYPE
		-> iterator_range<typename std::decay<Iterator1>::type>
#endif
	{
		typedef typename std::decay<Iterator1>::type iterator_type;
		BOOST_STATIC_ASSERT(std::is_same<iterator_type, typename std::decay<Iterator2>::type>::value);
		return iterator_range<iterator_type>(std::forward<Iterator1>(begin), std::forward<Iterator2>(end));
	}
}

#endif
<commit_msg>add make_iterator_range(Range) and make_contiguous_range<commit_after>#ifndef SILICIUM_ITERATOR_RANGE_HPP
#define SILICIUM_ITERATOR_RANGE_HPP

#include <silicium/config.hpp>
#include <boost/static_assert.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <cassert>

namespace Si
{
	namespace detail
	{
		//std::iterator_traits<T const *>::value_type seems to be T (GCC 4.8), but that
		//is not useful at all because the const is missing.
		template <class Iterator>
		struct actual_value_type
		{
			typedef typename std::remove_reference<decltype(*std::declval<Iterator>())>::type type;
		};
	}

	template <class Iterator>
	struct iterator_range
	{
		typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
		typedef typename detail::actual_value_type<Iterator>::type value_type;
		typedef Iterator iterator;
		typedef Iterator const_iterator;

		BOOST_CONSTEXPR iterator_range() BOOST_NOEXCEPT
			: m_begin(Iterator())
			, m_end(Iterator())
		{
		}

		template <class It1, class It2>
		BOOST_CONSTEXPR iterator_range(It1 &&begin, It2 &&end) BOOST_NOEXCEPT
			: m_begin(std::forward<It1>(begin))
			, m_end(std::forward<It2>(end))
		{
		}

		template <class OtherIterator>
		iterator_range(iterator_range<OtherIterator> const &other) BOOST_NOEXCEPT
			: m_begin(other.begin())
			, m_end(other.end())
		{
		}

		BOOST_CONSTEXPR Iterator const &begin() const BOOST_NOEXCEPT
		{
			return m_begin;
		}

		BOOST_CONSTEXPR Iterator const &end() const BOOST_NOEXCEPT
		{
			return m_end;
		}

		BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT
		{
			return m_begin == m_end;
		}

		BOOST_CONSTEXPR difference_type size() const BOOST_NOEXCEPT
		{
			return std::distance(m_begin, m_end);
		}

		SILICIUM_CXX14_CONSTEXPR void pop_front(difference_type n) BOOST_NOEXCEPT
		{
			assert(n <= size());
			std::advance(m_begin, n);
		}

		SILICIUM_CXX14_CONSTEXPR void pop_front() BOOST_NOEXCEPT
		{
			assert(!empty());
			pop_front(1);
		}

		value_type &front() const BOOST_NOEXCEPT
		{
			assert(!empty());
			return (*this)[0];
		}

		value_type &operator[](difference_type index) const BOOST_NOEXCEPT
		{
			assert(index < size());
			return begin()[index];
		}

	private:

		Iterator m_begin, m_end;
	};

	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &begin(iterator_range<Iterator> const &range)
	{
		return range.begin();
	}

	//for Boost.Range compatibility
	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &range_begin(iterator_range<Iterator> const &range)
	{
		return range.begin();
	}

	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &end(iterator_range<Iterator> const &range)
	{
		return range.end();
	}

	template <class Iterator1, class Iterator2>
	BOOST_CONSTEXPR auto make_iterator_range(Iterator1 &&begin, Iterator2 &&end)
#if !SILICIUM_COMPILER_HAS_AUTO_RETURN_TYPE
		-> iterator_range<typename std::decay<Iterator1>::type>
#endif
	{
		typedef typename std::decay<Iterator1>::type iterator_type;
		BOOST_STATIC_ASSERT(std::is_same<iterator_type, typename std::decay<Iterator2>::type>::value);
		return iterator_range<iterator_type>(std::forward<Iterator1>(begin), std::forward<Iterator2>(end));
	}

	template <class Range>
	auto make_iterator_range(Range &&range)
	{
		using std::begin;
		using std::end;
		return make_iterator_range(begin(range), end(range));
	}

	template <class ContiguousRange>
	auto make_contiguous_range(ContiguousRange &&range)
	{
		using std::begin;
		using std::end;
		auto * const data_begin = &*begin(range);
		auto * const data_end = &*end(range);
		return make_iterator_range(data_begin, data_end);
	}
}

#endif
<|endoftext|>


<commit_before>#ifndef SILICIUM_ITERATOR_RANGE_HPP
#define SILICIUM_ITERATOR_RANGE_HPP

#include <silicium/config.hpp>
#include <boost/static_assert.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <cassert>

namespace Si
{
	namespace detail
	{
		//std::iterator_traits<T const *>::value_type seems to be T (GCC 4.8), but that
		//is not useful at all because the const is missing.
		template <class Iterator>
		struct actual_value_type
		{
			typedef typename std::remove_reference<decltype(*std::declval<Iterator>())>::type type;
		};
	}

	template <class Iterator>
	struct iterator_range
	{
		typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
		typedef typename detail::actual_value_type<Iterator>::type value_type;
		typedef Iterator iterator;
		typedef Iterator const_iterator;

		BOOST_CONSTEXPR iterator_range() BOOST_NOEXCEPT
			: m_begin(Iterator())
			, m_end(Iterator())
		{
		}

		template <class It1, class It2>
		BOOST_CONSTEXPR iterator_range(It1 &&begin, It2 &&end) BOOST_NOEXCEPT
			: m_begin(std::forward<It1>(begin))
			, m_end(std::forward<It2>(end))
		{
		}

		template <class OtherIterator>
		iterator_range(iterator_range<OtherIterator> const &other) BOOST_NOEXCEPT
			: m_begin(other.begin())
			, m_end(other.end())
		{
		}

		BOOST_CONSTEXPR Iterator const &begin() const BOOST_NOEXCEPT
		{
			return m_begin;
		}

		BOOST_CONSTEXPR Iterator const &end() const BOOST_NOEXCEPT
		{
			return m_end;
		}

		BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT
		{
			return m_begin == m_end;
		}

		BOOST_CONSTEXPR difference_type size() const BOOST_NOEXCEPT
		{
			return std::distance(m_begin, m_end);
		}

		SILICIUM_CXX14_CONSTEXPR void pop_front(difference_type n) BOOST_NOEXCEPT
		{
			assert(n <= size());
			std::advance(m_begin, n);
		}

		SILICIUM_CXX14_CONSTEXPR void pop_front() BOOST_NOEXCEPT
		{
			assert(!empty());
			pop_front(1);
		}

		value_type &front() const BOOST_NOEXCEPT
		{
			assert(!empty());
			return (*this)[0];
		}

		value_type &operator[](difference_type index) const BOOST_NOEXCEPT
		{
			assert(index < size());
			return begin()[index];
		}

	private:

		Iterator m_begin, m_end;
	};

	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &begin(iterator_range<Iterator> const &range)
	{
		return range.begin();
	}

	//for Boost.Range compatibility
	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &range_begin(iterator_range<Iterator> const &range)
	{
		return range.begin();
	}

	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &end(iterator_range<Iterator> const &range)
	{
		return range.end();
	}

	template <class Iterator1, class Iterator2>
	BOOST_CONSTEXPR auto make_iterator_range(Iterator1 &&begin, Iterator2 &&end)
#if !SILICIUM_COMPILER_HAS_AUTO_RETURN_TYPE
		-> iterator_range<typename std::decay<Iterator1>::type>
#endif
	{
		typedef typename std::decay<Iterator1>::type iterator_type;
		BOOST_STATIC_ASSERT(std::is_same<iterator_type, typename std::decay<Iterator2>::type>::value);
		return iterator_range<iterator_type>(std::forward<Iterator1>(begin), std::forward<Iterator2>(end));
	}

	template <class Range>
	auto make_iterator_range(Range &&range)
#if !SILICIUM_COMPILER_HAS_AUTO_RETURN_TYPE
		-> decltype(make_iterator_range(std::begin(range), std::end(range)))
#endif
	{
		using std::begin;
		using std::end;
		return make_iterator_range(begin(range), end(range));
	}

	template <class ContiguousRange>
	auto make_contiguous_range(ContiguousRange &&range)
#if !SILICIUM_COMPILER_HAS_AUTO_RETURN_TYPE
		-> decltype(make_iterator_range(&*std::begin(range), &*std::end(range)))
#endif
	{
		using std::begin;
		using std::end;
		auto * const data_begin = &*begin(range);
		auto * const data_end = &*end(range);
		return make_iterator_range(data_begin, data_end);
	}
}

#endif
<commit_msg>do not dereference iterators that point past the end in make_contiguous_range<commit_after>#ifndef SILICIUM_ITERATOR_RANGE_HPP
#define SILICIUM_ITERATOR_RANGE_HPP

#include <silicium/config.hpp>
#include <boost/static_assert.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <cassert>

namespace Si
{
	namespace detail
	{
		//std::iterator_traits<T const *>::value_type seems to be T (GCC 4.8), but that
		//is not useful at all because the const is missing.
		template <class Iterator>
		struct actual_value_type
		{
			typedef typename std::remove_reference<decltype(*std::declval<Iterator>())>::type type;
		};
	}

	template <class Iterator>
	struct iterator_range
	{
		typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
		typedef typename detail::actual_value_type<Iterator>::type value_type;
		typedef Iterator iterator;
		typedef Iterator const_iterator;

		BOOST_CONSTEXPR iterator_range() BOOST_NOEXCEPT
			: m_begin(Iterator())
			, m_end(Iterator())
		{
		}

		template <class It1, class It2>
		BOOST_CONSTEXPR iterator_range(It1 &&begin, It2 &&end) BOOST_NOEXCEPT
			: m_begin(std::forward<It1>(begin))
			, m_end(std::forward<It2>(end))
		{
		}

		template <class OtherIterator>
		iterator_range(iterator_range<OtherIterator> const &other) BOOST_NOEXCEPT
			: m_begin(other.begin())
			, m_end(other.end())
		{
		}

		BOOST_CONSTEXPR Iterator const &begin() const BOOST_NOEXCEPT
		{
			return m_begin;
		}

		BOOST_CONSTEXPR Iterator const &end() const BOOST_NOEXCEPT
		{
			return m_end;
		}

		BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT
		{
			return m_begin == m_end;
		}

		BOOST_CONSTEXPR difference_type size() const BOOST_NOEXCEPT
		{
			return std::distance(m_begin, m_end);
		}

		SILICIUM_CXX14_CONSTEXPR void pop_front(difference_type n) BOOST_NOEXCEPT
		{
			assert(n <= size());
			std::advance(m_begin, n);
		}

		SILICIUM_CXX14_CONSTEXPR void pop_front() BOOST_NOEXCEPT
		{
			assert(!empty());
			pop_front(1);
		}

		value_type &front() const BOOST_NOEXCEPT
		{
			assert(!empty());
			return (*this)[0];
		}

		value_type &operator[](difference_type index) const BOOST_NOEXCEPT
		{
			assert(index < size());
			return begin()[index];
		}

	private:

		Iterator m_begin, m_end;
	};

	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &begin(iterator_range<Iterator> const &range)
	{
		return range.begin();
	}

	//for Boost.Range compatibility
	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &range_begin(iterator_range<Iterator> const &range)
	{
		return range.begin();
	}

	template <class Iterator>
	BOOST_CONSTEXPR Iterator const &end(iterator_range<Iterator> const &range)
	{
		return range.end();
	}

	template <class Iterator1, class Iterator2>
	BOOST_CONSTEXPR auto make_iterator_range(Iterator1 &&begin, Iterator2 &&end)
#if !SILICIUM_COMPILER_HAS_AUTO_RETURN_TYPE
		-> iterator_range<typename std::decay<Iterator1>::type>
#endif
	{
		typedef typename std::decay<Iterator1>::type iterator_type;
		BOOST_STATIC_ASSERT(std::is_same<iterator_type, typename std::decay<Iterator2>::type>::value);
		return iterator_range<iterator_type>(std::forward<Iterator1>(begin), std::forward<Iterator2>(end));
	}

	template <class Range>
	auto make_iterator_range(Range &&range)
#if !SILICIUM_COMPILER_HAS_AUTO_RETURN_TYPE
		-> decltype(make_iterator_range(std::begin(range), std::end(range)))
#endif
	{
		using std::begin;
		using std::end;
		return make_iterator_range(begin(range), end(range));
	}

	template <class ContiguousRange>
	auto make_contiguous_range(ContiguousRange &&range)
#if !SILICIUM_COMPILER_HAS_AUTO_RETURN_TYPE
		-> decltype(make_iterator_range(boost::addressof(*std::begin(range)), boost::addressof(*std::end(range))))
#endif
	{
		using std::begin;
		using std::end;
		auto begin_ = begin(range);
		auto end_ = end(range);
		if (begin_ == end_)
		{
			typename std::remove_reference<decltype(*begin_)>::type *data = nullptr;
			return make_iterator_range(data, data);
		}
		auto * const data_begin = boost::addressof(*begin_);
		auto * const data_end = data_begin + std::distance(begin_, end_);
		return make_iterator_range(data_begin, data_end);
	}
}

#endif
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

#include <cstdlib>
#include <cassert>
#include <ctime>
#include <stdexcept>
#include "core/core.hpp"
#include "core/jsonHelpers.hpp"
#include "core/command.hpp"
#include "core/command/commandMove.hpp"
#include "core/command/commandAttack.hpp"
#include "core/command/commandEndTurn.hpp"
#include "core/event/eventMove.hpp"
#include "core/event/eventAttack.hpp"
#include "core/event/eventEndTurn.hpp"
#include "core/player.hpp"
#include "core/lineOfSight.hpp"
#include "core/eventView.hpp"

Core::Core()
  : mConfig(parseJsonFile("confCore.json")),
    mCurrentPlayer(nullptr),
    mSelectedUnit(nullptr),
    mPathfinder(*this),
    mMap(V2i(0, 0)),
    mEventManager(*this)
{
  srand(std::time(nullptr));
  initUnitTypes();
  loadScenario();
}

Core::~Core() {
  for (auto* unitPointer : mUnits) {
    delete unitPointer;
  }
  for (auto* unitPointer : mDeadUnits) {
    delete unitPointer;
  }
  for (auto* playerPointer : mPlayers) {
    delete playerPointer;
  }
}

const std::list<Player*>& Core::players() const {
  return mPlayers;
}

const Player& Core::currentPlayer() const {
  assert(mCurrentPlayer);
  return *mCurrentPlayer;
}

Player& Core::currentPlayer() {
  return *mCurrentPlayer;
}

Unit& Core::selectedUnit() {
  return *mSelectedUnit;
}

bool Core::isAnyUnitSelected() const {
  return mSelectedUnit != NULL;
}

std::list<Unit*>& Core::units() {
  return mUnits;
}

std::list<Unit*>& Core::deadUnits() {
  return mDeadUnits;
}

Pathfinder& Core::pathfinder() {
  return mPathfinder;
}

const Pathfinder& Core::pathfinder() const {
  return mPathfinder;
}

const Map& Core::map() const {
  return mMap;
}

Map& Core::map() {
  return mMap;
}

EventManager& Core::eventManager() {
  return mEventManager;
}

const EventManager& Core::eventManager() const {
  return mEventManager;
}

std::list<EventView*>& Core::eventViewList(PlayerID playerID) {
  return mEventViewLists.at(playerID);
}

void Core::setSelectedUnit(Unit& unit) {
  mSelectedUnit = &unit;
}

void Core::deselectedAnyUnits() {
  mSelectedUnit = nullptr;
}

void Core::setCurrentPlayer(Player* player) {
  mCurrentPlayer = player;
}

void Core::doCommand(const Command& cmd) {
  switch (cmd.type()) {
  case CommandType::Move:
    command(dynamic_cast<const CommandMove&>(cmd));
    break;
  case CommandType::EndTurn:
    command(dynamic_cast<const CommandEndTurn&>(cmd));
    break;
  case CommandType::Attack:
    command(dynamic_cast<const CommandAttack&>(cmd));
    break;
  default:
    throw std::logic_error("default case");
  }
  processNewEvents();
}

void Core::processNewEvents() {
  while (!eventManager().isEmpty()) {
    Event* pointerToEvent = eventManager().popEvent();
    const Event& event = *pointerToEvent; // TODO: Fix memory leak
    event.apply(*this);
    for (Player* pPlayer : players()) {
      const Player& player = *pPlayer;
      EventView* eventView = eventToEventView(event); // TODO: send current player?
      mEventViewLists.at(player.id).push_back(eventView);
    }
  }
}

void Core::command(const CommandAttack& cmd) {
  const Unit& attacker = id2unit(cmd.attackerID());
  const Unit& victim = id2unit(cmd.victimID());
  if (isLineOfSightClear(attacker.position(), victim.position())
    && attacker.actionPoints() >= 3)
  {
    Event* e = EventAttack::generate(*this, attacker, victim);
    eventManager().addEvent(e);

  }
}

void Core::command(const CommandMove& cmd) {
  const Unit& unit = id2unit(cmd.unitID());
  const Tile& tile = map().tile(cmd.destination());
  int actionPoints = unit.actionPoints();
  if (tile.cost <= actionPoints && tile.parent.value() != DirID::NONE) {
    if (tile.cost <= actionPoints) {
      Event* e = EventMove::generate(*this, unit, cmd.destination());
      eventManager().addEvent(e);
    }
  }
}

void Core::command(const CommandEndTurn& cmd) {
  UNUSED(cmd);
  Event* e = EventEndTurn::generate(*this);
  eventManager().addEvent(e);
}

void Core::createLocalHumanPlayer(PlayerID id) {
  auto* p = new Player;
  mPlayers.push_back(p);
  p->id = id;
  {
    // create empty list object for EventViews
    mEventViewLists[id] = std::list<EventView*>();
  }
}

void Core::refreshUnits(PlayerID playerID) {
  for (auto* u : units()) {
    if (u->playerID() == playerID) {
      u->setActionPoints(u->type().actionPoints);
    }
  }
}

const UnitType& Core::unitType(const std::string& name) const {
  assert(mUnitTypes.count(name) != 0);
  return mUnitTypes.at(name);
}

bool Core::isLineOfSightClear(const V2i& from, const V2i& to) {
  LineOfSight los(from, to);
  for (V2i p = los.getNext(); !los.isFinished(); p = los.getNext()) {
#if 1
    // TODO: temp hack. fix los, remove this.
    if (!map().isInboard(p)) {
      return false;
    }
#endif
    if (isUnitAt(p) || map().tile(p).obstacle) {
      return false;
    }
  }
  return true;
}

void Core::cleanFow() {
  map().forEachTile([](Tile& tile) {
    tile.fow = 0;
  });
}

void Core::calculateFow() {
  map().forEachPosition([this](const V2i& p) {
    for (const auto* u : mUnits) {
      int maxDist = u->type().rangeOfVision;
      bool isPlayerOk = (u->playerID() == currentPlayer().id);
      bool isDistanceOk = (p.distance(u->position()) < maxDist);
      bool isLineOfSightOk = isLineOfSightClear(p, u->position());
      if (isPlayerOk && isDistanceOk && isLineOfSightOk) {
        ++(map().tile(p).fow);
      }
    }
  });
}

Unit& Core::unitAt(const V2i& position) {
  for (auto* u : mUnits) {
    if (u->position() == position) {
      return *u;
    }
  }
  throw std::invalid_argument("No unit at position!");
}

bool Core::isUnitAt(const V2i& position) const {
#if 0
  return (map().tile(position).unit != NULL);
#else
  for (auto* u : mUnits) {
    if (u->position() == position) {
      return true;
    }
  }
  return false;
#endif
}

Unit& Core::id2unit(UnitID id) {
  for (auto* u : mUnits) {
    if (u->id() == id) {
      return *u;
    }
  }
  throw std::invalid_argument("No unit with this ID!");
}

// TODO: actually _DO_ something!
EventView* Core::eventToEventView(const Event& event) {
  switch (event.type()) {
  case EventType::Move:
    return new EventMoveView(dynamic_cast<const EventMove&>(event));
  case EventType::EndTurn:
    return new EventEndTurnView(dynamic_cast<const EventEndTurn&>(event));
  case EventType::Attack:
    return new EventAttackView(dynamic_cast<const EventAttack&>(event));
  default:
    throw std::logic_error("default case!");
  }
}

void Core::initUnitTypes() {
  Json::Value config = parseJsonFile("unitTypes.json");
  for (const std::string& unitTypeName : config.getMemberNames()) {
    UnitType unitType = parseUnitTypeInfo(config[unitTypeName]);
    mUnitTypes[unitTypeName] = unitType;
  }
}

UnitType Core::parseUnitTypeInfo(const Json::Value& unitTypeInfo) const {
  UnitType unitType;
  unitType.rangeOfVision = unitTypeInfo["rangeOfVision"].asInt();
  unitType.actionPoints = unitTypeInfo["actionPoints"].asInt();
  unitType.id = mUnitTypes.size();
  return unitType;
}

UnitID Core::getNewUnitID() const {
  if (!mUnits.empty()) {
    auto* lastUnit = mUnits.back();
    return lastUnit->id() + 1;
  } else {
    return 0;
  }
}

void Core::addUnit(
    const V2i& p,
    PlayerID playerID,
    const UnitType& unitType,
    const Dir& dir)
{
  assert(map().isInboard(p));
  auto* u = new Unit(getNewUnitID(), playerID, unitType);
  u->setPosition(p);
  u->setDirection(dir);
  u->setActionPoints(u->type().actionPoints);
  mUnits.push_back(u);
  if (isAnyUnitSelected()) {
    pathfinder().fillMap(selectedUnit());
  }
  calculateFow();
}

void Core::loadScenario() {
  Json::Value scenario = parseJsonFile("scenario.json");
  // players
  {
    int playersCount = scenario["playersCount"].asInt();
    for (PlayerID id = 0; id < playersCount; ++id) {
      createLocalHumanPlayer(id);
    }
    setCurrentPlayer(mPlayers.back()); // Important!
  }
  // map
  {
    Json::Value mapFile = parseJsonFile(scenario["map"].asString());
    mMap = Map(JsonValueToV2i(mapFile["mapSize"]));
    Json::Value RowsOfTiles = mapFile["tiles"];
    int y = 0;
    for (const Json::Value& rowOfTiles : RowsOfTiles) {
      int x = 0;
      for (const Json::Value& tile : rowOfTiles) {
        V2i p(x, y);
        bool isObstacle = (tile.asString() == "obstacle");
        map().tile(p).obstacle = isObstacle;
        ++x;
      }
      ++y;
    }
  }
  // units
  {
    Json::Value unitsData = scenario["units"];
    PlayerID playerID = 0;
    for (const Json::Value& playerUnitData : unitsData) {
      for (const Json::Value& unitInfo : playerUnitData) {
        V2i position = JsonValueToV2i(unitInfo["position"]);
        std::string typeName = unitInfo["type"].asString();
        Dir direction(unitInfo["direction"].asInt());
        addUnit(position, playerID, unitType(typeName), direction);
      }
      ++playerID;
    }
    calculateFow();
  }
}
<commit_msg>Core::isLineOfSightClear(..): Removed temp '#if..' block<commit_after>// See LICENSE file for copyright and license details.

#include <cstdlib>
#include <cassert>
#include <ctime>
#include <stdexcept>
#include "core/core.hpp"
#include "core/jsonHelpers.hpp"
#include "core/command.hpp"
#include "core/command/commandMove.hpp"
#include "core/command/commandAttack.hpp"
#include "core/command/commandEndTurn.hpp"
#include "core/event/eventMove.hpp"
#include "core/event/eventAttack.hpp"
#include "core/event/eventEndTurn.hpp"
#include "core/player.hpp"
#include "core/lineOfSight.hpp"
#include "core/eventView.hpp"

Core::Core()
  : mConfig(parseJsonFile("confCore.json")),
    mCurrentPlayer(nullptr),
    mSelectedUnit(nullptr),
    mPathfinder(*this),
    mMap(V2i(0, 0)),
    mEventManager(*this)
{
  srand(std::time(nullptr));
  initUnitTypes();
  loadScenario();
}

Core::~Core() {
  for (auto* unitPointer : mUnits) {
    delete unitPointer;
  }
  for (auto* unitPointer : mDeadUnits) {
    delete unitPointer;
  }
  for (auto* playerPointer : mPlayers) {
    delete playerPointer;
  }
}

const std::list<Player*>& Core::players() const {
  return mPlayers;
}

const Player& Core::currentPlayer() const {
  assert(mCurrentPlayer);
  return *mCurrentPlayer;
}

Player& Core::currentPlayer() {
  return *mCurrentPlayer;
}

Unit& Core::selectedUnit() {
  return *mSelectedUnit;
}

bool Core::isAnyUnitSelected() const {
  return mSelectedUnit != NULL;
}

std::list<Unit*>& Core::units() {
  return mUnits;
}

std::list<Unit*>& Core::deadUnits() {
  return mDeadUnits;
}

Pathfinder& Core::pathfinder() {
  return mPathfinder;
}

const Pathfinder& Core::pathfinder() const {
  return mPathfinder;
}

const Map& Core::map() const {
  return mMap;
}

Map& Core::map() {
  return mMap;
}

EventManager& Core::eventManager() {
  return mEventManager;
}

const EventManager& Core::eventManager() const {
  return mEventManager;
}

std::list<EventView*>& Core::eventViewList(PlayerID playerID) {
  return mEventViewLists.at(playerID);
}

void Core::setSelectedUnit(Unit& unit) {
  mSelectedUnit = &unit;
}

void Core::deselectedAnyUnits() {
  mSelectedUnit = nullptr;
}

void Core::setCurrentPlayer(Player* player) {
  mCurrentPlayer = player;
}

void Core::doCommand(const Command& cmd) {
  switch (cmd.type()) {
  case CommandType::Move:
    command(dynamic_cast<const CommandMove&>(cmd));
    break;
  case CommandType::EndTurn:
    command(dynamic_cast<const CommandEndTurn&>(cmd));
    break;
  case CommandType::Attack:
    command(dynamic_cast<const CommandAttack&>(cmd));
    break;
  default:
    throw std::logic_error("default case");
  }
  processNewEvents();
}

void Core::processNewEvents() {
  while (!eventManager().isEmpty()) {
    Event* pointerToEvent = eventManager().popEvent();
    const Event& event = *pointerToEvent; // TODO: Fix memory leak
    event.apply(*this);
    for (Player* pPlayer : players()) {
      const Player& player = *pPlayer;
      EventView* eventView = eventToEventView(event); // TODO: send current player?
      mEventViewLists.at(player.id).push_back(eventView);
    }
  }
}

void Core::command(const CommandAttack& cmd) {
  const Unit& attacker = id2unit(cmd.attackerID());
  const Unit& victim = id2unit(cmd.victimID());
  if (isLineOfSightClear(attacker.position(), victim.position())
    && attacker.actionPoints() >= 3)
  {
    Event* e = EventAttack::generate(*this, attacker, victim);
    eventManager().addEvent(e);

  }
}

void Core::command(const CommandMove& cmd) {
  const Unit& unit = id2unit(cmd.unitID());
  const Tile& tile = map().tile(cmd.destination());
  int actionPoints = unit.actionPoints();
  if (tile.cost <= actionPoints && tile.parent.value() != DirID::NONE) {
    if (tile.cost <= actionPoints) {
      Event* e = EventMove::generate(*this, unit, cmd.destination());
      eventManager().addEvent(e);
    }
  }
}

void Core::command(const CommandEndTurn& cmd) {
  UNUSED(cmd);
  Event* e = EventEndTurn::generate(*this);
  eventManager().addEvent(e);
}

void Core::createLocalHumanPlayer(PlayerID id) {
  auto* p = new Player;
  mPlayers.push_back(p);
  p->id = id;
  {
    // create empty list object for EventViews
    mEventViewLists[id] = std::list<EventView*>();
  }
}

void Core::refreshUnits(PlayerID playerID) {
  for (auto* u : units()) {
    if (u->playerID() == playerID) {
      u->setActionPoints(u->type().actionPoints);
    }
  }
}

const UnitType& Core::unitType(const std::string& name) const {
  assert(mUnitTypes.count(name) != 0);
  return mUnitTypes.at(name);
}

bool Core::isLineOfSightClear(const V2i& from, const V2i& to) {
  LineOfSight los(from, to);
  for (V2i p = los.getNext(); !los.isFinished(); p = los.getNext()) {
    if (isUnitAt(p) || map().tile(p).obstacle) {
      return false;
    }
  }
  return true;
}

void Core::cleanFow() {
  map().forEachTile([](Tile& tile) {
    tile.fow = 0;
  });
}

void Core::calculateFow() {
  map().forEachPosition([this](const V2i& p) {
    for (const auto* u : mUnits) {
      int maxDist = u->type().rangeOfVision;
      bool isPlayerOk = (u->playerID() == currentPlayer().id);
      bool isDistanceOk = (p.distance(u->position()) < maxDist);
      bool isLineOfSightOk = isLineOfSightClear(p, u->position());
      if (isPlayerOk && isDistanceOk && isLineOfSightOk) {
        ++(map().tile(p).fow);
      }
    }
  });
}

Unit& Core::unitAt(const V2i& position) {
  for (auto* u : mUnits) {
    if (u->position() == position) {
      return *u;
    }
  }
  throw std::invalid_argument("No unit at position!");
}

bool Core::isUnitAt(const V2i& position) const {
#if 0
  return (map().tile(position).unit != NULL);
#else
  for (auto* u : mUnits) {
    if (u->position() == position) {
      return true;
    }
  }
  return false;
#endif
}

Unit& Core::id2unit(UnitID id) {
  for (auto* u : mUnits) {
    if (u->id() == id) {
      return *u;
    }
  }
  throw std::invalid_argument("No unit with this ID!");
}

// TODO: actually _DO_ something!
EventView* Core::eventToEventView(const Event& event) {
  switch (event.type()) {
  case EventType::Move:
    return new EventMoveView(dynamic_cast<const EventMove&>(event));
  case EventType::EndTurn:
    return new EventEndTurnView(dynamic_cast<const EventEndTurn&>(event));
  case EventType::Attack:
    return new EventAttackView(dynamic_cast<const EventAttack&>(event));
  default:
    throw std::logic_error("default case!");
  }
}

void Core::initUnitTypes() {
  Json::Value config = parseJsonFile("unitTypes.json");
  for (const std::string& unitTypeName : config.getMemberNames()) {
    UnitType unitType = parseUnitTypeInfo(config[unitTypeName]);
    mUnitTypes[unitTypeName] = unitType;
  }
}

UnitType Core::parseUnitTypeInfo(const Json::Value& unitTypeInfo) const {
  UnitType unitType;
  unitType.rangeOfVision = unitTypeInfo["rangeOfVision"].asInt();
  unitType.actionPoints = unitTypeInfo["actionPoints"].asInt();
  unitType.id = mUnitTypes.size();
  return unitType;
}

UnitID Core::getNewUnitID() const {
  if (!mUnits.empty()) {
    auto* lastUnit = mUnits.back();
    return lastUnit->id() + 1;
  } else {
    return 0;
  }
}

void Core::addUnit(
    const V2i& p,
    PlayerID playerID,
    const UnitType& unitType,
    const Dir& dir)
{
  assert(map().isInboard(p));
  auto* u = new Unit(getNewUnitID(), playerID, unitType);
  u->setPosition(p);
  u->setDirection(dir);
  u->setActionPoints(u->type().actionPoints);
  mUnits.push_back(u);
  if (isAnyUnitSelected()) {
    pathfinder().fillMap(selectedUnit());
  }
  calculateFow();
}

void Core::loadScenario() {
  Json::Value scenario = parseJsonFile("scenario.json");
  // players
  {
    int playersCount = scenario["playersCount"].asInt();
    for (PlayerID id = 0; id < playersCount; ++id) {
      createLocalHumanPlayer(id);
    }
    setCurrentPlayer(mPlayers.back()); // Important!
  }
  // map
  {
    Json::Value mapFile = parseJsonFile(scenario["map"].asString());
    mMap = Map(JsonValueToV2i(mapFile["mapSize"]));
    Json::Value RowsOfTiles = mapFile["tiles"];
    int y = 0;
    for (const Json::Value& rowOfTiles : RowsOfTiles) {
      int x = 0;
      for (const Json::Value& tile : rowOfTiles) {
        V2i p(x, y);
        bool isObstacle = (tile.asString() == "obstacle");
        map().tile(p).obstacle = isObstacle;
        ++x;
      }
      ++y;
    }
  }
  // units
  {
    Json::Value unitsData = scenario["units"];
    PlayerID playerID = 0;
    for (const Json::Value& playerUnitData : unitsData) {
      for (const Json::Value& unitInfo : playerUnitData) {
        V2i position = JsonValueToV2i(unitInfo["position"]);
        std::string typeName = unitInfo["type"].asString();
        Dir direction(unitInfo["direction"].asInt());
        addUnit(position, playerID, unitType(typeName), direction);
      }
      ++playerID;
    }
    calculateFow();
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef PRINT_HH_
#define PRINT_HH_

#include <boost/format.hpp>
#include <iostream>

inline void
apply_format(boost::format& fmt) {
}

template <typename A0, typename... Arest>
inline void
apply_format(boost::format& fmt, A0&& a0, Arest&&... arest) {
    apply_format(fmt % std::forward<A0>(a0), std::forward<Arest>(arest)...);
}

template <typename... A>
std::ostream&
fprint(std::ostream& os, boost::format& fmt, A&&... a) {
    apply_format(fmt, std::forward<A>(a)...);
    return os << fmt;
}

template <typename... A>
void
print(boost::format& fmt, A&&... a) {
    fprint(std::cout, fmt, std::forward<A>(a)...);
}

template <typename... A>
std::ostream&
fprint(std::ostream& os, const char* fmt, A&&... a) {
    boost::format bfmt(fmt);
    return fprint(os, bfmt, std::forward<A>(a)...);
}

template <typename... A>
void
print(const char* fmt, A&&... a) {
    boost::format bfmt(fmt);
    return print(bfmt, std::forward<A>(a)...);
}

template <typename... A>
std::string
sprint(const char* fmt, A&&... a) {
    boost::format bfmt(fmt);
    apply_format(bfmt, std::forward<A>(a)...);
    return bfmt.str();
}

#endif /* PRINT_HH_ */
<commit_msg>core: add format_separated()<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#ifndef PRINT_HH_
#define PRINT_HH_

#include <boost/format.hpp>
#include <iostream>

inline void
apply_format(boost::format& fmt) {
}

template <typename A0, typename... Arest>
inline void
apply_format(boost::format& fmt, A0&& a0, Arest&&... arest) {
    apply_format(fmt % std::forward<A0>(a0), std::forward<Arest>(arest)...);
}

template <typename... A>
std::ostream&
fprint(std::ostream& os, boost::format& fmt, A&&... a) {
    apply_format(fmt, std::forward<A>(a)...);
    return os << fmt;
}

template <typename... A>
void
print(boost::format& fmt, A&&... a) {
    fprint(std::cout, fmt, std::forward<A>(a)...);
}

template <typename... A>
std::ostream&
fprint(std::ostream& os, const char* fmt, A&&... a) {
    boost::format bfmt(fmt);
    return fprint(os, bfmt, std::forward<A>(a)...);
}

template <typename... A>
void
print(const char* fmt, A&&... a) {
    boost::format bfmt(fmt);
    return print(bfmt, std::forward<A>(a)...);
}

template <typename... A>
std::string
sprint(const char* fmt, A&&... a) {
    boost::format bfmt(fmt);
    apply_format(bfmt, std::forward<A>(a)...);
    return bfmt.str();
}

template <typename Iterator>
std::string
format_separated(Iterator b, Iterator e, const char* sep = ", ") {
    std::string ret;
    if (b == e) {
        return ret;
    }
    ret += *b++;
    while (b != e) {
        ret += sep;
        ret += *b++;
    }
    return ret;
}

#endif /* PRINT_HH_ */
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2013 Danny Y., Rapptz

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef SOL_STACK_HPP
#define SOL_STACK_HPP

#include "reference.hpp"
#include "tuple.hpp"
#include "traits.hpp"
#include <utility>
#include <array>
#include <cstring>

namespace sol {
namespace stack {
namespace detail {
template<typename T>
inline T get_unsigned(lua_State* L, std::true_type, int index = -1) {
    return lua_tounsigned(L, index);
}

template<typename T>
inline T get_unsigned(lua_State* L, std::false_type, int index = -1) {
    return static_cast<T>(lua_tointeger(L, index));
}

template<typename T>
inline T get_arithmetic(lua_State* L, std::false_type, int index = -1) {
    // T is a floating point
    return lua_tonumber(L, index);
}

template<typename T>
inline T get_arithmetic(lua_State* L, std::true_type, int index = -1) {
    // T is an integral
    return get_unsigned<T>(L, std::is_unsigned<T>{}, index);
}

template<typename T>
inline T get_nil(lua_State* L, std::true_type, int index = -1) {
    if (lua_isnil(L, index) == 0)
        throw sol::sol_error("not nil");
    return nil_t{};
}

template<typename T>
inline T get_nil(lua_State* L, std::false_type, int index = -1) {
    // T is a class type
    return T(L, index);
}

template<typename T>
inline T get_helper(lua_State* L, std::true_type, int index = -1) {
    return get_nil<T>(L, std::is_same<nil_t, T>(), index);
}

template<typename T>
inline T get_helper(lua_State* L, std::false_type, int index = -1) {
    // T is a fundamental type
    return get_arithmetic<T>(L, std::is_integral<T>{}, index);
}

template<typename T>
inline void push_unsigned(lua_State* L, T x, std::true_type) {
    lua_pushunsigned(L, x);
}

template<typename T>
inline void push_unsigned(lua_State* L, T x, std::false_type) {
    lua_pushinteger(L, x);
}

template<typename T>
inline void push_arithmetic(lua_State* L, T x, std::true_type) {
    // T is an integral type
    push_unsigned(L, x, std::is_unsigned<T>{});
}

template<typename T>
inline void push_arithmetic(lua_State* L, T x, std::false_type) {
    // T is an floating point type
    lua_pushnumber(L, x);
}
} // detail

template<typename T>
inline T get(lua_State* L, int index = -1) {
    return detail::get_helper<T>(L, std::is_class<T>{}, index);
}

template<>
inline bool get<bool>(lua_State* L, int index) {
    return lua_toboolean(L, index) != 0;
}

template<>
inline std::string get<std::string>(lua_State* L, int index) {
    std::string::size_type len;
    auto str = lua_tolstring(L, index, &len);
    return { str, len };
}

template<>
inline const char* get<const char*>(lua_State* L, int index) {
    return lua_tostring(L, index);
}

template<typename T>
inline T pop(lua_State* L) {
    auto r = get<T>(L);
    lua_pop(L, 1);
    return r;
}

template<typename T>
inline EnableIf<std::is_arithmetic<T>> push(lua_State* L, T arithmetic) {
    detail::push_arithmetic(L, arithmetic, std::is_integral<T>{});
}

inline void push(lua_State*, reference& ref) {
    ref.push();
}

inline void push(lua_State* L, bool boolean) {
    lua_pushboolean(L, boolean);
}

inline void push(lua_State* L, const nil_t&) {
    lua_pushnil(L);
}

inline void push(lua_State* L, lua_CFunction func) {
    lua_pushcfunction(L, func);
}

inline void push(lua_State* L, lua_CFunction func, int n) {
    lua_pushcclosure(L, func, n);
}

inline void push(lua_State* L, void* userdata) {
    lua_pushlightuserdata(L, userdata);
}

template<size_t N>
inline void push(lua_State* L, const char (&str)[N]) {
    lua_pushlstring(L, str, N - 1);
}

inline void push(lua_State* L, const char* str) {
    lua_pushlstring(L, str, std::char_traits<char>::length(str));
}

inline void push(lua_State* L, const std::string& str) {
    lua_pushlstring(L, str.c_str(), str.size());
}

template<typename T>
inline void push_user(lua_State* L, T& userdata, const char* metatablekey) {
    T* pdatum = static_cast<T*>(lua_newuserdata(L, sizeof(T)));
    T& datum = *pdatum;
    datum = userdata;
    if (metatablekey != nullptr) {
        lua_getfield(L, LUA_REGISTRYINDEX, metatablekey);
        lua_setmetatable(L, -2);
    }
}

template<typename T, size_t N>
inline void push(lua_State* L, const std::array<T, N>& data) {
    for (auto&& i : data) {
        push(L, i);
    }
}

template<typename T>
inline int push_user(lua_State* L, T& item) {
    typedef typename std::decay<T>::type TValue;
    const static std::size_t itemsize = sizeof(TValue);
    const static std::size_t voidsize = sizeof(void*);
    const static std::size_t voidsizem1 = voidsize - 1;
    const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize;
    typedef std::array<void*, data_t_count> data_t;

    data_t data{{}};
    std::memcpy(std::addressof(data[0]), std::addressof(item), itemsize);
    push(L, data);
    return data_t_count;
}

namespace detail {
template<typename T, std::size_t... I>
inline void push(lua_State* L, indices<I...>, const T& tuplen) {
    using swallow = char[ 1 + sizeof...(I) ];
    swallow {'\0', (sol::stack::push(L, std::get<I>(tuplen)), '\0')... };
}

template<typename F, typename... Vs>
auto ltr_pop(lua_State*, F&& f, types<>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)...)) {
    return f(std::forward<Vs>(vs)...);
}
template<typename F, typename Head, typename... Vs>
auto ltr_pop(lua_State* L, F&& f, types<Head>, Vs&&... vs) -> decltype(ltr_pop(L, std::forward<F>(f), types<>(), std::forward<Vs>(vs)..., pop<Head>(L))) {
    return ltr_pop(L, std::forward<F>(f), types<>(), std::forward<Vs>(vs)..., pop<Head>(L));
}
template<typename F, typename Head, typename... Tail, typename... Vs>
auto ltr_pop(lua_State* L, F&& f, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)..., std::declval<Head>(), std::declval<Tail>()...)) {
    return ltr_pop(L, std::forward<F>(f), types<Tail...>(), std::forward<Vs>(vs)..., pop<Head>(L));
}
} // detail

template<typename... Args>
inline void push(lua_State* L, const std::tuple<Args...>& tuplen) {
    detail::push(L, build_indices<sizeof...(Args)>(), tuplen);
}

template<typename... Args, typename TFx>
inline auto pop_call(lua_State* L, TFx&& fx, types<Args...>) -> decltype(detail::ltr_pop(L, std::forward<TFx>(fx), types<Args...>())) {
    return detail::ltr_pop(L, std::forward<TFx>(fx), types<Args...>());
}

template<typename... Args>
void push_args(lua_State* L, Args&&... args) {
    using swallow = char[];
    void(swallow{'\0', (stack::push(L, std::forward<Args>(args)), '\0')... });
}
} // stack
} // sol

#endif // SOL_STACK_HPP<commit_msg>Cast result of floating point retrieval before receiving it<commit_after>// The MIT License (MIT)

// Copyright (c) 2013 Danny Y., Rapptz

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef SOL_STACK_HPP
#define SOL_STACK_HPP

#include "reference.hpp"
#include "tuple.hpp"
#include "traits.hpp"
#include <utility>
#include <array>
#include <cstring>

namespace sol {
namespace stack {
namespace detail {
template<typename T>
inline T get_unsigned(lua_State* L, std::true_type, int index = -1) {
    return lua_tounsigned(L, index);
}

template<typename T>
inline T get_unsigned(lua_State* L, std::false_type, int index = -1) {
    return static_cast<T>(lua_tointeger(L, index));
}

template<typename T>
inline T get_arithmetic(lua_State* L, std::false_type, int index = -1) {
    // T is a floating point
    return static_cast<T>(lua_tonumber(L, index));
}

template<typename T>
inline T get_arithmetic(lua_State* L, std::true_type, int index = -1) {
    // T is an integral
    return get_unsigned<T>(L, std::is_unsigned<T>{}, index);
}

template<typename T>
inline T get_nil(lua_State* L, std::true_type, int index = -1) {
    if (lua_isnil(L, index) == 0)
        throw sol::sol_error("not nil");
    return nil_t{};
}

template<typename T>
inline T get_nil(lua_State* L, std::false_type, int index = -1) {
    // T is a class type
    return T(L, index);
}

template<typename T>
inline T get_helper(lua_State* L, std::true_type, int index = -1) {
    return get_nil<T>(L, std::is_same<nil_t, T>(), index);
}

template<typename T>
inline T get_helper(lua_State* L, std::false_type, int index = -1) {
    // T is a fundamental type
    return get_arithmetic<T>(L, std::is_integral<T>{}, index);
}

template<typename T>
inline void push_unsigned(lua_State* L, T x, std::true_type) {
    lua_pushunsigned(L, x);
}

template<typename T>
inline void push_unsigned(lua_State* L, T x, std::false_type) {
    lua_pushinteger(L, x);
}

template<typename T>
inline void push_arithmetic(lua_State* L, T x, std::true_type) {
    // T is an integral type
    push_unsigned(L, x, std::is_unsigned<T>{});
}

template<typename T>
inline void push_arithmetic(lua_State* L, T x, std::false_type) {
    // T is an floating point type
    lua_pushnumber(L, x);
}
} // detail

template<typename T>
inline T get(lua_State* L, int index = -1) {
    return detail::get_helper<T>(L, std::is_class<T>{}, index);
}

template<>
inline bool get<bool>(lua_State* L, int index) {
    return lua_toboolean(L, index) != 0;
}

template<>
inline std::string get<std::string>(lua_State* L, int index) {
    std::string::size_type len;
    auto str = lua_tolstring(L, index, &len);
    return { str, len };
}

template<>
inline const char* get<const char*>(lua_State* L, int index) {
    return lua_tostring(L, index);
}

template<typename T>
inline T pop(lua_State* L) {
    auto r = get<T>(L);
    lua_pop(L, 1);
    return r;
}

template<typename T>
inline EnableIf<std::is_arithmetic<T>> push(lua_State* L, T arithmetic) {
    detail::push_arithmetic(L, arithmetic, std::is_integral<T>{});
}

inline void push(lua_State*, reference& ref) {
    ref.push();
}

inline void push(lua_State* L, bool boolean) {
    lua_pushboolean(L, boolean);
}

inline void push(lua_State* L, const nil_t&) {
    lua_pushnil(L);
}

inline void push(lua_State* L, lua_CFunction func) {
    lua_pushcfunction(L, func);
}

inline void push(lua_State* L, lua_CFunction func, int n) {
    lua_pushcclosure(L, func, n);
}

inline void push(lua_State* L, void* userdata) {
    lua_pushlightuserdata(L, userdata);
}

template<size_t N>
inline void push(lua_State* L, const char (&str)[N]) {
    lua_pushlstring(L, str, N - 1);
}

inline void push(lua_State* L, const char* str) {
    lua_pushlstring(L, str, std::char_traits<char>::length(str));
}

inline void push(lua_State* L, const std::string& str) {
    lua_pushlstring(L, str.c_str(), str.size());
}

template<typename T>
inline void push_user(lua_State* L, T& userdata, const char* metatablekey) {
    T* pdatum = static_cast<T*>(lua_newuserdata(L, sizeof(T)));
    T& datum = *pdatum;
    datum = userdata;
    if (metatablekey != nullptr) {
        lua_getfield(L, LUA_REGISTRYINDEX, metatablekey);
        lua_setmetatable(L, -2);
    }
}

template<typename T, size_t N>
inline void push(lua_State* L, const std::array<T, N>& data) {
    for (auto&& i : data) {
        push(L, i);
    }
}

template<typename T>
inline int push_user(lua_State* L, T& item) {
    typedef typename std::decay<T>::type TValue;
    const static std::size_t itemsize = sizeof(TValue);
    const static std::size_t voidsize = sizeof(void*);
    const static std::size_t voidsizem1 = voidsize - 1;
    const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize;
    typedef std::array<void*, data_t_count> data_t;

    data_t data{{}};
    std::memcpy(std::addressof(data[0]), std::addressof(item), itemsize);
    push(L, data);
    return data_t_count;
}

namespace detail {
template<typename T, std::size_t... I>
inline void push(lua_State* L, indices<I...>, const T& tuplen) {
    using swallow = char[ 1 + sizeof...(I) ];
    swallow {'\0', (sol::stack::push(L, std::get<I>(tuplen)), '\0')... };
}

template<typename F, typename... Vs>
auto ltr_pop(lua_State*, F&& f, types<>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)...)) {
    return f(std::forward<Vs>(vs)...);
}
template<typename F, typename Head, typename... Vs>
auto ltr_pop(lua_State* L, F&& f, types<Head>, Vs&&... vs) -> decltype(ltr_pop(L, std::forward<F>(f), types<>(), std::forward<Vs>(vs)..., pop<Head>(L))) {
    return ltr_pop(L, std::forward<F>(f), types<>(), std::forward<Vs>(vs)..., pop<Head>(L));
}
template<typename F, typename Head, typename... Tail, typename... Vs>
auto ltr_pop(lua_State* L, F&& f, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::forward<Vs>(vs)..., std::declval<Head>(), std::declval<Tail>()...)) {
    return ltr_pop(L, std::forward<F>(f), types<Tail...>(), std::forward<Vs>(vs)..., pop<Head>(L));
}
} // detail

template<typename... Args>
inline void push(lua_State* L, const std::tuple<Args...>& tuplen) {
    detail::push(L, build_indices<sizeof...(Args)>(), tuplen);
}

template<typename... Args, typename TFx>
inline auto pop_call(lua_State* L, TFx&& fx, types<Args...>) -> decltype(detail::ltr_pop(L, std::forward<TFx>(fx), types<Args...>())) {
    return detail::ltr_pop(L, std::forward<TFx>(fx), types<Args...>());
}

template<typename... Args>
void push_args(lua_State* L, Args&&... args) {
    using swallow = char[];
    void(swallow{'\0', (stack::push(L, std::forward<Args>(args)), '\0')... });
}
} // stack
} // sol

#endif // SOL_STACK_HPP<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <iostream>
#include <fstream>
#include <iomanip>

#include <minizinc/model.hh>
#include <minizinc/parser.hh>
#include <minizinc/prettyprinter.hh>
#include <minizinc/typecheck.hh>
#include <minizinc/astexception.hh>
#include <minizinc/hash.hh>
#include <minizinc/eval_par.hh>
#include <minizinc/builtins.hh>
#include <minizinc/file_utils.hh>
#include <minizinc/timer.hh>

using namespace MiniZinc;
using namespace std;

std::string stoptime(Timer& timer) {
  std::ostringstream oss;
  oss << std::setprecision(0) << std::fixed << timer.ms() << " ms";
  return oss.str();
}

int main(int argc, char** argv) {
  Timer starttime;
  string filename;

  string flag_output_file;

  bool flag_output_comments = true;
  bool flag_output_flush = true;
  bool flag_output_time = false;
  string solfile;
  int flag_ignore_lines = 0;
  istream& solstream = cin;

  string solution_separator = "----------";
  string solution_comma     = "";
  string unsatisfiable_msg  = "=====UNSATISFIABLE=====";
  string unbounded_msg      = "=====UNBOUNDED=====";
  string unknown_msg        = "=====UNKNOWN=====";
  string search_complete_msg= "==========";

  vector<string> includePaths;
  string std_lib_dir;
  if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) {
    std_lib_dir = string(MZNSTDLIBDIR);
  }

  if (argc < 2)
    goto error;

  for (int i=1; i<argc; i++) {
    if (string(argv[i])==string("--version")) {
      std::cout << "NICTA MiniZinc solution printing tool, version "
      << MZN_VERSION_MAJOR << "." << MZN_VERSION_MINOR << "." << MZN_VERSION_PATCH << std::endl;
      std::cout << "Copyright (C) 2014, 2015 Monash University and NICTA" << std::endl;
      std::exit(EXIT_SUCCESS);
    }
    if (string(argv[i])==string("-h") || string(argv[i])==string("--help")) {
        goto error;
    } else if (string(argv[i])=="-o" || string(argv[i])=="--output-to-file") {
      i++;
      if (i==argc)
        goto error;
      flag_output_file = argv[i];
    } else if (string(argv[i])=="--stdlib-dir") {
      i++;
      if (i==argc)
        goto error;
      std_lib_dir = argv[i];
    } else if (string(argv[i])=="--no-flush-output") {
      flag_output_flush = false;
    } else if (string(argv[i])=="--no-output-comments") {
      flag_output_comments = false;
    } else if (string(argv[i])=="-i" ||
               string(argv[i])=="--ignore-lines" ||
               string(argv[i])=="--ignore-leading-lines") {
      ++i;
      if (i==argc)
        goto error;
      flag_ignore_lines = atoi(argv[i]);
    } else if (string(argv[i])=="--soln-sep" ||
               string(argv[i])=="--soln-separator" ||
               string(argv[i])=="--solution-separator") {
      ++i;
      if (i==argc)
        goto error;
      solution_separator = string(argv[i]);
    } else if (string(argv[i])=="--soln-comma" ||
               string(argv[i])=="--solution-comma") {
      ++i;
      if (i==argc)
        goto error;
      solution_comma = string(argv[i]);
    } else if (string(argv[i])=="--unsat-msg" ||
               string(argv[i])=="--unsatisfiable-msg") {
      ++i;
      if (i==argc)
        goto error;
      unsatisfiable_msg = string(argv[i]);
    } else if (string(argv[i])=="--unbounded-msg") {
      ++i;
      if (i==argc)
        goto error;
      unbounded_msg = string(argv[i]);
    } else if (string(argv[i])=="--unknown-msg") {
      ++i;
      if (i==argc)
        goto error;
      unknown_msg = string(argv[i]);
    } else if (string(argv[i])=="--search-complete-msg") {
      ++i;
      if (i==argc)
        goto error;
      search_complete_msg = string(argv[i]);
    } else if (string(argv[i])=="--output-time") {
      flag_output_time = true;
    } else {
      filename = argv[i++];
      if (filename.length()<=4 ||
          filename.substr(filename.length()-4,string::npos) != ".ozn") {
        std::cerr << "Invalid .ozn file " << filename << "." << std::endl;
        goto error;
      }
    }
  }

  if (std_lib_dir=="") {
    std::string mypath = FileUtils::progpath();
    if (!mypath.empty()) {
      if (FileUtils::file_exists(mypath+"/share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/share/minizinc";
      } else if (FileUtils::file_exists(mypath+"/../share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/../share/minizinc";
      } else if (FileUtils::file_exists(mypath+"/../../share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/../../share/minizinc";
      }
    }
  }

  if (std_lib_dir=="") {
    std::cerr << "Error: unknown minizinc standard library directory.\n"
    << "Specify --stdlib-dir on the command line or set the\n"
    << "MZN_STDLIB_DIR environment variable.\n";
    std::exit(EXIT_FAILURE);
  }

  includePaths.push_back(std_lib_dir+"/std/");

  {
    if (Model* outputm = parse(filename, std::vector<std::string>(), includePaths, false, false, false,
                               std::cerr)) {
      try {
        std::vector<TypeError> typeErrors;
        Env env(outputm);
        MiniZinc::typecheck(env,outputm,typeErrors);
        MiniZinc::registerBuiltins(env,outputm);

        typedef pair<VarDecl*,Expression*> DE;
        ASTStringMap<DE>::t declmap;
        Expression* outputExpr = NULL;
        for (unsigned int i=0; i<outputm->size(); i++) {
          if (VarDeclI* vdi = (*outputm)[i]->dyn_cast<VarDeclI>()) {
            declmap.insert(pair<ASTString,DE>(vdi->e()->id()->v(),DE(vdi->e(),vdi->e()->e())));
          } else if (OutputI* oi = (*outputm)[i]->dyn_cast<OutputI>()) {
            outputExpr = oi->e();
          }
        }

        //ostream& fout(flag_output_file.empty() ? std::cout : new fstream(flag_output_file));
        fstream file_ostream;
        if (!flag_output_file.empty())
            file_ostream.open(flag_output_file.c_str(), std::fstream::out);
        ostream& fout = flag_output_file.empty() ? std::cout : file_ostream;

        int solutions_found = 0;

        string solution;
        string comments;
        for (;;) {
          if (solstream.good()) {
            string line;
            getline(solstream, line);
            if (flag_ignore_lines > 0) {
              flag_ignore_lines--;
              continue;
            }
            if (line=="----------") {
              ++solutions_found;
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              // Put the "solution comma" before the solution itself,
              // but only for solutions after the first one.
              if (solutions_found > 1 && !solution_comma.empty())
                fout << solution_comma << std::endl;
              if (outputExpr != NULL) {
                for (unsigned int i=0; i<outputm->size(); i++) {
                  if (VarDeclI* vdi = (*outputm)[i]->dyn_cast<VarDeclI>()) {
                    ASTStringMap<DE>::t::iterator it = declmap.find(vdi->e()->id()->v());
                    vdi->e()->e(it->second.second);
                    vdi->e()->evaluated(false);
                  }
                }
                Model* sm = parseFromString(solution, "solution.szn", includePaths, true, false, false, cerr);
                for (unsigned int i=0; i<sm->size(); i++) {
                  if (AssignI* ai = (*sm)[i]->dyn_cast<AssignI>()) {
                    ASTStringMap<DE>::t::iterator it = declmap.find(ai->id());
                    if (it==declmap.end()) {
                      cerr << "Error: unexpected identifier " << ai->id() << " in output\n";
                      exit(EXIT_FAILURE);
                    }
                    ai->e()->type(it->second.first->type());
                    ai->decl(it->second.first);
                    typecheck(env,outputm, ai);
                    if (Call* c = ai->e()->dyn_cast<Call>()) {
                      // This is an arrayXd call, make sure we get the right builtin
                      assert(c->args()[c->args().size()-1]->isa<ArrayLit>());
                      for (unsigned int i=0; i<c->args().size(); i++)
                        c->args()[i]->type(Type::parsetint());
                      c->args()[c->args().size()-1]->type(it->second.first->type());
                      c->decl(outputm->matchFn(env.envi(),c));
                    }
                    it->second.first->e(ai->e());
                  }
                }

                GCLock lock;
                ArrayLit* al = eval_array_lit(env.envi(),outputExpr);
                std::string os;
                for (unsigned int i=0; i<al->v().size(); i++) {
                  std::string s = eval_string(env.envi(),al->v()[i]);
                  if (!s.empty()) {
                    os = s;
                    fout << os;
                    if (flag_output_flush)
                      fout.flush();
                  }
                }
                if (!os.empty() && os[os.size()-1] != '\n')
                  fout << std::endl;
                  if (flag_output_flush)
                    fout.flush();
              }
              fout << comments;
              fout << solution_separator << std::endl;
              if (flag_output_flush)
                fout.flush();
              solution = "";
              comments = "";
            } else if (line=="==========") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << search_complete_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNSATISFIABLE=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unsatisfiable_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNBOUNDED=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unbounded_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNKNOWN=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unknown_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else {
              solution += line+"\n";
              size_t comment_pos = line.find('%');
              if (comment_pos != string::npos) {
                comments += line.substr(comment_pos);
                comments += "\n";
              }
            }
          } else {
            break;
          }
        }
        fout << comments;
        if (flag_output_flush)
          fout.flush();
      } catch (LocationException& e) {
        std::cerr << e.what() << ": " << e.msg() << std::endl;
        std::cerr << e.loc() << std::endl;
        exit(EXIT_FAILURE);
      } catch (Exception& e) {
        std::cerr << e.what() << ": " << e.msg() << std::endl;
        exit(EXIT_FAILURE);
      }
      delete outputm;
    }
  }

  return 0;

error:
  std::cerr << "Usage: "<< argv[0]
            << " [<options>] <model>.ozn" << std::endl
            << std::endl
            << "Options:" << std::endl
            << "  --help, -h\n    Print this help message." << std::endl
            << "  --version\n    Print version information." << std::endl
            << "  -o <file>, --output-to-file <file>\n    Filename for generated output." << std::endl
            << "  --stdlib-dir <dir>\n    Path to MiniZinc standard library directory." << std::endl
            << "  --no-output-comments\n    Do not print comments in the FlatZinc solution stream." << std::endl
            << "  --output-time\n    Print timing information in the FlatZinc solution stream." << std::endl
            << "  --no-flush-output\n    Don't flush output stream after every line." << std::endl
            << "  -i <n>, --ignore-lines <n>, --ignore-leading-lines <n>\n    Ignore the first <n> lines in the FlatZinc solution stream." << std::endl
            << "  --soln-sep <s>, --soln-separator <s>, --solution-separator <s>\n    Specify the string printed after each solution.\n    The default is to use the same as FlatZinc,\n    \"----------\"." << std::endl
            << "  --soln-comma <s>, --solution-comma <s>\n    Specify the string used to separate solutions.\n    The default is the empty string." << std::endl
            << "  --unsat-msg <msg>, --unsatisfiable-msg <msg>\n    Specify the message to print if the model instance is\n    unsatisfiable.\n    The default is to print \"=====UNSATISFIABLE=====\"." << std::endl
            << "  --unbounded-msg <msg>\n    Specify the message to print if the objective of the\n    model instance is unbounded.\n    The default is to print \"=====UNBOUNDED=====\"." << std::endl
            << "  --unknown-msg <msg>\n    Specify the message to print if search terminates without\n    the entire search space having been explored and no\n    solution has been found.\n    The default is to print \"=====UNKNOWN=====\"." << std::endl
            << "  --search-complete-msg <msg>\n    Specify the message to print if search terminates having\n    explored the entire search space.\n    The default is to print \"==========\"." << std::endl
  ;

  exit(EXIT_FAILURE);
}
<commit_msg>Fix memory leak in solns2out (fixes #36).<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <iostream>
#include <fstream>
#include <iomanip>

#include <minizinc/model.hh>
#include <minizinc/parser.hh>
#include <minizinc/prettyprinter.hh>
#include <minizinc/typecheck.hh>
#include <minizinc/astexception.hh>
#include <minizinc/hash.hh>
#include <minizinc/eval_par.hh>
#include <minizinc/builtins.hh>
#include <minizinc/file_utils.hh>
#include <minizinc/timer.hh>

using namespace MiniZinc;
using namespace std;

std::string stoptime(Timer& timer) {
  std::ostringstream oss;
  oss << std::setprecision(0) << std::fixed << timer.ms() << " ms";
  return oss.str();
}

int main(int argc, char** argv) {
  Timer starttime;
  string filename;

  string flag_output_file;

  bool flag_output_comments = true;
  bool flag_output_flush = true;
  bool flag_output_time = false;
  string solfile;
  int flag_ignore_lines = 0;
  istream& solstream = cin;

  string solution_separator = "----------";
  string solution_comma     = "";
  string unsatisfiable_msg  = "=====UNSATISFIABLE=====";
  string unbounded_msg      = "=====UNBOUNDED=====";
  string unknown_msg        = "=====UNKNOWN=====";
  string search_complete_msg= "==========";

  vector<string> includePaths;
  string std_lib_dir;
  if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) {
    std_lib_dir = string(MZNSTDLIBDIR);
  }

  if (argc < 2)
    goto error;

  for (int i=1; i<argc; i++) {
    if (string(argv[i])==string("--version")) {
      std::cout << "NICTA MiniZinc solution printing tool, version "
      << MZN_VERSION_MAJOR << "." << MZN_VERSION_MINOR << "." << MZN_VERSION_PATCH << std::endl;
      std::cout << "Copyright (C) 2014, 2015 Monash University and NICTA" << std::endl;
      std::exit(EXIT_SUCCESS);
    }
    if (string(argv[i])==string("-h") || string(argv[i])==string("--help")) {
        goto error;
    } else if (string(argv[i])=="-o" || string(argv[i])=="--output-to-file") {
      i++;
      if (i==argc)
        goto error;
      flag_output_file = argv[i];
    } else if (string(argv[i])=="--stdlib-dir") {
      i++;
      if (i==argc)
        goto error;
      std_lib_dir = argv[i];
    } else if (string(argv[i])=="--no-flush-output") {
      flag_output_flush = false;
    } else if (string(argv[i])=="--no-output-comments") {
      flag_output_comments = false;
    } else if (string(argv[i])=="-i" ||
               string(argv[i])=="--ignore-lines" ||
               string(argv[i])=="--ignore-leading-lines") {
      ++i;
      if (i==argc)
        goto error;
      flag_ignore_lines = atoi(argv[i]);
    } else if (string(argv[i])=="--soln-sep" ||
               string(argv[i])=="--soln-separator" ||
               string(argv[i])=="--solution-separator") {
      ++i;
      if (i==argc)
        goto error;
      solution_separator = string(argv[i]);
    } else if (string(argv[i])=="--soln-comma" ||
               string(argv[i])=="--solution-comma") {
      ++i;
      if (i==argc)
        goto error;
      solution_comma = string(argv[i]);
    } else if (string(argv[i])=="--unsat-msg" ||
               string(argv[i])=="--unsatisfiable-msg") {
      ++i;
      if (i==argc)
        goto error;
      unsatisfiable_msg = string(argv[i]);
    } else if (string(argv[i])=="--unbounded-msg") {
      ++i;
      if (i==argc)
        goto error;
      unbounded_msg = string(argv[i]);
    } else if (string(argv[i])=="--unknown-msg") {
      ++i;
      if (i==argc)
        goto error;
      unknown_msg = string(argv[i]);
    } else if (string(argv[i])=="--search-complete-msg") {
      ++i;
      if (i==argc)
        goto error;
      search_complete_msg = string(argv[i]);
    } else if (string(argv[i])=="--output-time") {
      flag_output_time = true;
    } else {
      filename = argv[i++];
      if (filename.length()<=4 ||
          filename.substr(filename.length()-4,string::npos) != ".ozn") {
        std::cerr << "Invalid .ozn file " << filename << "." << std::endl;
        goto error;
      }
    }
  }

  if (std_lib_dir=="") {
    std::string mypath = FileUtils::progpath();
    if (!mypath.empty()) {
      if (FileUtils::file_exists(mypath+"/share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/share/minizinc";
      } else if (FileUtils::file_exists(mypath+"/../share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/../share/minizinc";
      } else if (FileUtils::file_exists(mypath+"/../../share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/../../share/minizinc";
      }
    }
  }

  if (std_lib_dir=="") {
    std::cerr << "Error: unknown minizinc standard library directory.\n"
    << "Specify --stdlib-dir on the command line or set the\n"
    << "MZN_STDLIB_DIR environment variable.\n";
    std::exit(EXIT_FAILURE);
  }

  includePaths.push_back(std_lib_dir+"/std/");

  {
    if (Model* outputm = parse(filename, std::vector<std::string>(), includePaths, false, false, false,
                               std::cerr)) {
      try {
        std::vector<TypeError> typeErrors;
        Env env(outputm);
        MiniZinc::typecheck(env,outputm,typeErrors);
        MiniZinc::registerBuiltins(env,outputm);

        typedef pair<VarDecl*,Expression*> DE;
        ASTStringMap<DE>::t declmap;
        Expression* outputExpr = NULL;
        for (unsigned int i=0; i<outputm->size(); i++) {
          if (VarDeclI* vdi = (*outputm)[i]->dyn_cast<VarDeclI>()) {
            declmap.insert(pair<ASTString,DE>(vdi->e()->id()->v(),DE(vdi->e(),vdi->e()->e())));
          } else if (OutputI* oi = (*outputm)[i]->dyn_cast<OutputI>()) {
            outputExpr = oi->e();
          }
        }

        //ostream& fout(flag_output_file.empty() ? std::cout : new fstream(flag_output_file));
        fstream file_ostream;
        if (!flag_output_file.empty())
            file_ostream.open(flag_output_file.c_str(), std::fstream::out);
        ostream& fout = flag_output_file.empty() ? std::cout : file_ostream;

        int solutions_found = 0;

        string solution;
        string comments;
        for (;;) {
          if (solstream.good()) {
            string line;
            getline(solstream, line);
            if (flag_ignore_lines > 0) {
              flag_ignore_lines--;
              continue;
            }
            if (line=="----------") {
              ++solutions_found;
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              // Put the "solution comma" before the solution itself,
              // but only for solutions after the first one.
              if (solutions_found > 1 && !solution_comma.empty())
                fout << solution_comma << std::endl;
              if (outputExpr != NULL) {
                for (unsigned int i=0; i<outputm->size(); i++) {
                  if (VarDeclI* vdi = (*outputm)[i]->dyn_cast<VarDeclI>()) {
                    ASTStringMap<DE>::t::iterator it = declmap.find(vdi->e()->id()->v());
                    vdi->e()->e(it->second.second);
                    vdi->e()->evaluated(false);
                  }
                }
                Model* sm = parseFromString(solution, "solution.szn", includePaths, true, false, false, cerr);
                for (unsigned int i=0; i<sm->size(); i++) {
                  if (AssignI* ai = (*sm)[i]->dyn_cast<AssignI>()) {
                    ASTStringMap<DE>::t::iterator it = declmap.find(ai->id());
                    if (it==declmap.end()) {
                      cerr << "Error: unexpected identifier " << ai->id() << " in output\n";
                      exit(EXIT_FAILURE);
                    }
                    ai->e()->type(it->second.first->type());
                    ai->decl(it->second.first);
                    typecheck(env,outputm, ai);
                    if (Call* c = ai->e()->dyn_cast<Call>()) {
                      // This is an arrayXd call, make sure we get the right builtin
                      assert(c->args()[c->args().size()-1]->isa<ArrayLit>());
                      for (unsigned int i=0; i<c->args().size(); i++)
                        c->args()[i]->type(Type::parsetint());
                      c->args()[c->args().size()-1]->type(it->second.first->type());
                      c->decl(outputm->matchFn(env.envi(),c));
                    }
                    it->second.first->e(ai->e());
                  }
                }
                delete sm;

                GCLock lock;
                ArrayLit* al = eval_array_lit(env.envi(),outputExpr);
                std::string os;
                for (unsigned int i=0; i<al->v().size(); i++) {
                  std::string s = eval_string(env.envi(),al->v()[i]);
                  if (!s.empty()) {
                    os = s;
                    fout << os;
                    if (flag_output_flush)
                      fout.flush();
                  }
                }
                if (!os.empty() && os[os.size()-1] != '\n')
                  fout << std::endl;
                  if (flag_output_flush)
                    fout.flush();
              }
              fout << comments;
              fout << solution_separator << std::endl;
              if (flag_output_flush)
                fout.flush();
              solution = "";
              comments = "";
            } else if (line=="==========") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << search_complete_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNSATISFIABLE=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unsatisfiable_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNBOUNDED=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unbounded_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNKNOWN=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unknown_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else {
              solution += line+"\n";
              size_t comment_pos = line.find('%');
              if (comment_pos != string::npos) {
                comments += line.substr(comment_pos);
                comments += "\n";
              }
            }
          } else {
            break;
          }
        }
        fout << comments;
        if (flag_output_flush)
          fout.flush();
      } catch (LocationException& e) {
        std::cerr << e.what() << ": " << e.msg() << std::endl;
        std::cerr << e.loc() << std::endl;
        exit(EXIT_FAILURE);
      } catch (Exception& e) {
        std::cerr << e.what() << ": " << e.msg() << std::endl;
        exit(EXIT_FAILURE);
      }
      delete outputm;
    }
  }

  return 0;

error:
  std::cerr << "Usage: "<< argv[0]
            << " [<options>] <model>.ozn" << std::endl
            << std::endl
            << "Options:" << std::endl
            << "  --help, -h\n    Print this help message." << std::endl
            << "  --version\n    Print version information." << std::endl
            << "  -o <file>, --output-to-file <file>\n    Filename for generated output." << std::endl
            << "  --stdlib-dir <dir>\n    Path to MiniZinc standard library directory." << std::endl
            << "  --no-output-comments\n    Do not print comments in the FlatZinc solution stream." << std::endl
            << "  --output-time\n    Print timing information in the FlatZinc solution stream." << std::endl
            << "  --no-flush-output\n    Don't flush output stream after every line." << std::endl
            << "  -i <n>, --ignore-lines <n>, --ignore-leading-lines <n>\n    Ignore the first <n> lines in the FlatZinc solution stream." << std::endl
            << "  --soln-sep <s>, --soln-separator <s>, --solution-separator <s>\n    Specify the string printed after each solution.\n    The default is to use the same as FlatZinc,\n    \"----------\"." << std::endl
            << "  --soln-comma <s>, --solution-comma <s>\n    Specify the string used to separate solutions.\n    The default is the empty string." << std::endl
            << "  --unsat-msg <msg>, --unsatisfiable-msg <msg>\n    Specify the message to print if the model instance is\n    unsatisfiable.\n    The default is to print \"=====UNSATISFIABLE=====\"." << std::endl
            << "  --unbounded-msg <msg>\n    Specify the message to print if the objective of the\n    model instance is unbounded.\n    The default is to print \"=====UNBOUNDED=====\"." << std::endl
            << "  --unknown-msg <msg>\n    Specify the message to print if search terminates without\n    the entire search space having been explored and no\n    solution has been found.\n    The default is to print \"=====UNKNOWN=====\"." << std::endl
            << "  --search-complete-msg <msg>\n    Specify the message to print if search terminates having\n    explored the entire search space.\n    The default is to print \"==========\"." << std::endl
  ;

  exit(EXIT_FAILURE);
}
<|endoftext|>