<commit_before>#include "AsioTcpSocket.hpp"
#include "AsioService.hpp"
#include "../MemoryFile.hpp"
#include "../PartFile.hpp"
#include "../CriticalCode.hpp"
#include <boost/bind.hpp>

BEGIN_INANITY_NET

const size_t AsioTcpSocket::receiveFileSize = 0x1000;

AsioTcpSocket::SendItem::SendItem(ptr<File> data, ptr<SendHandler> handler)
: data(data), handler(handler) {}

/// Вспомогательный класс последовательности буферов.
/** Удовлетворяет требованиям Asio к ConstBufferSequence. */
class AsioTcpSocket::Buffers
{
private:
	typedef std::deque<SendItem>::const_iterator InternalIterator;

public:
	/// Класс буфера.
	class Buffer
	{
	private:
		/// Файл с данными.
		ptr<File> file;
		/// Смещение от начала, которое нужно пропустить.
		size_t skip;

	public:
		Buffer(ptr<File> file, size_t skip) : file(file), skip(skip) {}

		operator boost::asio::const_buffer() const
		{
			return boost::asio::const_buffer((const void*)*this, (size_t)*this);
		}

		operator const void*() const
		{
			return (const char*)file->GetData() + skip;
		}

		operator size_t() const
		{
			return file->GetSize() - skip;
		}
	};

	typedef Buffer value_type;

	/// Класс константного итератора.
	class ConstIterator
	{
	private:
		const Buffers& buffers;
		InternalIterator it;

	public:
		ConstIterator(const Buffers& buffers, InternalIterator it) : buffers(buffers), it(it) {}

		const Buffer operator*() const
		{
			return Buffer(it->data, it == buffers.beginIt ? buffers.firstSkip : 0);
		}
		ConstIterator& operator++()
		{
			++it;
			return *this;
		}
		ConstIterator operator++(int)
		{
			ConstIterator temp(*this);
			++it;
			return temp;
		}
		ConstIterator& operator--()
		{
			--it;
			return *this;
		}
		ConstIterator operator--(int)
		{
			ConstIterator temp(*this);
			--it;
			return temp;
		}
		friend bool operator==(const ConstIterator& a, const ConstIterator& b)
		{
			return a.it == b.it;
		}
		friend bool operator!=(const ConstIterator& a, const ConstIterator& b)
		{
			return a.it != b.it;
		}
	};

	typedef ConstIterator const_iterator;

private:
	// Границы посылки.
	InternalIterator beginIt, endIt;
	/// Сколько следует пропустить от начала первого буфера.
	size_t firstSkip;

public:
	Buffers(InternalIterator begin, InternalIterator end, size_t firstSkip)
	: beginIt(begin), endIt(end), firstSkip(firstSkip) {}

	ConstIterator begin() const
	{
		return ConstIterator(*this, beginIt);
	}
	ConstIterator end() const
	{
		return ConstIterator(*this, endIt);
	}
};

/// Вспомогательный класс для обработчика завершения отправки.
class AsioTcpSocket::SentBinder
{
private:
	ptr<AsioTcpSocket> socket;

public:
	SentBinder(ptr<AsioTcpSocket> socket) : socket(socket) {}

	void operator()(const boost::system::error_code& error, size_t transferred) const
	{
		socket->Sent(error, transferred);
	}
};

/// Вспомогательный класс для обработчика принятия данных.
class AsioTcpSocket::ReceivedBinder
{
private:
	ptr<AsioTcpSocket> socket;

public:
	ReceivedBinder(ptr<AsioTcpSocket> socket) : socket(socket) {}

	void operator()(const boost::system::error_code& error, size_t transferred) const
	{
		socket->Received(error, transferred);
	}
};

AsioTcpSocket::AsioTcpSocket(ptr<AsioService> service)
	: service(service), socket(service->GetIoService()),
	firstItemSent(0), sendClosed(false) {}

boost::asio::ip::tcp::socket& AsioTcpSocket::GetSocket()
{
	return socket;
}

void AsioTcpSocket::StartSending()
{
	// если в очереди ничего нет, проверить, не нужно ли закрыть сокет
	if(sendQueue.empty())
	{
		if(sendClosed)
			try
			{
				socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send);
			}
			catch(boost::system::system_error error)
			{
				THROW_SECONDARY("Can't close Asio TCP socket", AsioService::ConvertError(error));
			}
	}
	else
	{
		// очередь не пуста, начинаем отправку
		socket.async_write_some(Buffers(sendQueue.begin(), sendQueue.end(), firstItemSent), SentBinder(this));
	}
}

void AsioTcpSocket::Sent(const boost::system::error_code& error, size_t transferred)
{
	// если произошла ошибка
	if(error)
	{
		ptr<Exception> exception = AsioService::ConvertError(error);

		// отправить её всем элементам в очереди, и очистить очередь

		// скопируем обработчики в вектор, чтобы вызывать их
		// вне блокировки, и обеспечить реентрантность
		std::vector<ptr<SendHandler> > handlers;
		{
			CriticalCode cc(cs);
			handlers.resize(sendQueue.size());
			size_t j = 0;
			for(std::deque<SendItem>::iterator i = sendQueue.begin(); i != sendQueue.end(); ++i)
				handlers[j++] = i->handler;
			sendQueue.clear();
		}

		for(size_t j = 0; j < handlers.size(); ++j)
			if(handlers[j])
				handlers[j]->FireError(exception);

		return;
	}
	// ошибки нет
	else
	{
		// уведомить все завершившиеся файлы, и удалить их из очереди

		// скопируем обработчики в вектор, чтобы вызывать их
		// вне блокировки, и обеспечить реентрантность
		std::vector<ptr<SendHandler> > handlers;
		{
			CriticalCode cc(cs);
			std::deque<SendItem>::iterator i;
			size_t j = 0;
			for(i = sendQueue.begin(); i != sendQueue.end(); ++i)
			{
				const SendItem& item = *i;
				// если элемент не передался полностью, закончить
				size_t itemDataSkip = i == sendQueue.begin() ? firstItemSent : 0;
				size_t itemSize = item.data->GetSize() - itemDataSkip;
				if(itemSize > transferred)
				{
					// этот элемент теперь будет первым, выставить новое смещение
					firstItemSent = itemDataSkip + transferred;
					break;
				}
				// иначе передался полностью
				transferred -= itemSize;
				// добавить обработчик в массив
				if(item.handler)
					handlers.push_back(item.handler);
			}
			// теперь i указывает на первый элемент, который ещё не передался
			// удалить всё, что до него
			sendQueue.erase(sendQueue.begin(), i);

			// если в очереди что-то есть, запустить отправку снова
			StartSending();
		}

		for(size_t j = 0; j < handlers.size(); ++j)
			handlers[j]->FireSuccess();
	}
}

void AsioTcpSocket::StartReceiving()
{
	receiveFile = NEW(MemoryFile(receiveFileSize));
	socket.async_read_some(boost::asio::buffer(receiveFile->GetData(), receiveFileSize), ReceivedBinder(this));
}

void AsioTcpSocket::Received(const boost::system::error_code& error, size_t transferred)
{
	ptr<ReceiveHandler> receiveHandler;
	ptr<File> receiveFile;

	{
		CriticalCode cc(cs);

		receiveHandler = this->receiveHandler;
		receiveFile = this->receiveFile;

		if(error)
		{
			CloseNonSynced();
			this->receiveHandler = 0;
			this->receiveFile = 0;
		}
		else
			StartReceiving();
	}

	if(receiveHandler)
	{
		if(error)
		{
			// если корректный конец файла, это не ошибка
			if(error == boost::asio::error::eof)
				receiveHandler->FireData(0);
			else
				receiveHandler->FireError(AsioService::ConvertError(error));
		}
		else
			receiveHandler->FireData(NEW(PartFile(receiveFile, receiveFile->GetData(), transferred)));
	}
}

void AsioTcpSocket::CloseNonSynced()
{
	try
	{
		socket.close();
	}
	catch(boost::system::system_error error)
	{
	}
}

void AsioTcpSocket::Send(ptr<File> file, ptr<SendHandler> sendHandler)
{
	try
	{
		CriticalCode cc(cs);

		// если запланировано закрытие передачи, то больше в очередь добавлять ничего нельзя
		if(sendClosed)
			THROW("Sending closed");

		bool queueWasEmpty = sendQueue.empty();

		// добавить элемент в очередь
		sendQueue.push_back(SendItem(file, sendHandler));

		// сбросить количество переданных данных в первом элементе,
		// если очередь была пуста (то есть первый элемент как раз
		// был добавлен)
		// также, если очередь была пуста, начать отправку
		if(queueWasEmpty)
		{
			firstItemSent = 0;
			StartSending();
		}
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY("Can't send data to Asio TCP socket", exception);
	}
}

void AsioTcpSocket::End()
{
	CriticalCode cc(cs);

	if(!sendClosed)
	{
		sendClosed = true;

		if(sendQueue.empty())
			StartSending();
	}
}

void AsioTcpSocket::SetReceiveHandler(ptr<ReceiveHandler> receiveHandler)
{
	CriticalCode cc(cs);

	bool firstTime = !this->receiveHandler;
	this->receiveHandler = receiveHandler;

	if(firstTime)
		// запустить приём
		StartReceiving();
}

void AsioTcpSocket::Close()
{
	CriticalCode cc(cs);

	CloseNonSynced();
}

END_INANITY_NET
<commit_msg>remove unneeded variable<commit_after>#include "AsioTcpSocket.hpp"
#include "AsioService.hpp"
#include "../MemoryFile.hpp"
#include "../PartFile.hpp"
#include "../CriticalCode.hpp"
#include <boost/bind.hpp>

BEGIN_INANITY_NET

const size_t AsioTcpSocket::receiveFileSize = 0x1000;

AsioTcpSocket::SendItem::SendItem(ptr<File> data, ptr<SendHandler> handler)
: data(data), handler(handler) {}

/// Вспомогательный класс последовательности буферов.
/** Удовлетворяет требованиям Asio к ConstBufferSequence. */
class AsioTcpSocket::Buffers
{
private:
	typedef std::deque<SendItem>::const_iterator InternalIterator;

public:
	/// Класс буфера.
	class Buffer
	{
	private:
		/// Файл с данными.
		ptr<File> file;
		/// Смещение от начала, которое нужно пропустить.
		size_t skip;

	public:
		Buffer(ptr<File> file, size_t skip) : file(file), skip(skip) {}

		operator boost::asio::const_buffer() const
		{
			return boost::asio::const_buffer((const void*)*this, (size_t)*this);
		}

		operator const void*() const
		{
			return (const char*)file->GetData() + skip;
		}

		operator size_t() const
		{
			return file->GetSize() - skip;
		}
	};

	typedef Buffer value_type;

	/// Класс константного итератора.
	class ConstIterator
	{
	private:
		const Buffers& buffers;
		InternalIterator it;

	public:
		ConstIterator(const Buffers& buffers, InternalIterator it) : buffers(buffers), it(it) {}

		const Buffer operator*() const
		{
			return Buffer(it->data, it == buffers.beginIt ? buffers.firstSkip : 0);
		}
		ConstIterator& operator++()
		{
			++it;
			return *this;
		}
		ConstIterator operator++(int)
		{
			ConstIterator temp(*this);
			++it;
			return temp;
		}
		ConstIterator& operator--()
		{
			--it;
			return *this;
		}
		ConstIterator operator--(int)
		{
			ConstIterator temp(*this);
			--it;
			return temp;
		}
		friend bool operator==(const ConstIterator& a, const ConstIterator& b)
		{
			return a.it == b.it;
		}
		friend bool operator!=(const ConstIterator& a, const ConstIterator& b)
		{
			return a.it != b.it;
		}
	};

	typedef ConstIterator const_iterator;

private:
	// Границы посылки.
	InternalIterator beginIt, endIt;
	/// Сколько следует пропустить от начала первого буфера.
	size_t firstSkip;

public:
	Buffers(InternalIterator begin, InternalIterator end, size_t firstSkip)
	: beginIt(begin), endIt(end), firstSkip(firstSkip) {}

	ConstIterator begin() const
	{
		return ConstIterator(*this, beginIt);
	}
	ConstIterator end() const
	{
		return ConstIterator(*this, endIt);
	}
};

/// Вспомогательный класс для обработчика завершения отправки.
class AsioTcpSocket::SentBinder
{
private:
	ptr<AsioTcpSocket> socket;

public:
	SentBinder(ptr<AsioTcpSocket> socket) : socket(socket) {}

	void operator()(const boost::system::error_code& error, size_t transferred) const
	{
		socket->Sent(error, transferred);
	}
};

/// Вспомогательный класс для обработчика принятия данных.
class AsioTcpSocket::ReceivedBinder
{
private:
	ptr<AsioTcpSocket> socket;

public:
	ReceivedBinder(ptr<AsioTcpSocket> socket) : socket(socket) {}

	void operator()(const boost::system::error_code& error, size_t transferred) const
	{
		socket->Received(error, transferred);
	}
};

AsioTcpSocket::AsioTcpSocket(ptr<AsioService> service)
	: service(service), socket(service->GetIoService()),
	firstItemSent(0), sendClosed(false) {}

boost::asio::ip::tcp::socket& AsioTcpSocket::GetSocket()
{
	return socket;
}

void AsioTcpSocket::StartSending()
{
	// если в очереди ничего нет, проверить, не нужно ли закрыть сокет
	if(sendQueue.empty())
	{
		if(sendClosed)
			try
			{
				socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send);
			}
			catch(boost::system::system_error error)
			{
				THROW_SECONDARY("Can't close Asio TCP socket", AsioService::ConvertError(error));
			}
	}
	else
	{
		// очередь не пуста, начинаем отправку
		socket.async_write_some(Buffers(sendQueue.begin(), sendQueue.end(), firstItemSent), SentBinder(this));
	}
}

void AsioTcpSocket::Sent(const boost::system::error_code& error, size_t transferred)
{
	// если произошла ошибка
	if(error)
	{
		ptr<Exception> exception = AsioService::ConvertError(error);

		// отправить её всем элементам в очереди, и очистить очередь

		// скопируем обработчики в вектор, чтобы вызывать их
		// вне блокировки, и обеспечить реентрантность
		std::vector<ptr<SendHandler> > handlers;
		{
			CriticalCode cc(cs);
			handlers.resize(sendQueue.size());
			size_t j = 0;
			for(std::deque<SendItem>::iterator i = sendQueue.begin(); i != sendQueue.end(); ++i)
				handlers[j++] = i->handler;
			sendQueue.clear();
		}

		for(size_t j = 0; j < handlers.size(); ++j)
			if(handlers[j])
				handlers[j]->FireError(exception);

		return;
	}
	// ошибки нет
	else
	{
		// уведомить все завершившиеся файлы, и удалить их из очереди

		// скопируем обработчики в вектор, чтобы вызывать их
		// вне блокировки, и обеспечить реентрантность
		std::vector<ptr<SendHandler> > handlers;
		{
			CriticalCode cc(cs);
			std::deque<SendItem>::iterator i;
			for(i = sendQueue.begin(); i != sendQueue.end(); ++i)
			{
				const SendItem& item = *i;
				// если элемент не передался полностью, закончить
				size_t itemDataSkip = i == sendQueue.begin() ? firstItemSent : 0;
				size_t itemSize = item.data->GetSize() - itemDataSkip;
				if(itemSize > transferred)
				{
					// этот элемент теперь будет первым, выставить новое смещение
					firstItemSent = itemDataSkip + transferred;
					break;
				}
				// иначе передался полностью
				transferred -= itemSize;
				// добавить обработчик в массив
				if(item.handler)
					handlers.push_back(item.handler);
			}
			// теперь i указывает на первый элемент, который ещё не передался
			// удалить всё, что до него
			sendQueue.erase(sendQueue.begin(), i);

			// если в очереди что-то есть, запустить отправку снова
			StartSending();
		}

		for(size_t j = 0; j < handlers.size(); ++j)
			handlers[j]->FireSuccess();
	}
}

void AsioTcpSocket::StartReceiving()
{
	receiveFile = NEW(MemoryFile(receiveFileSize));
	socket.async_read_some(boost::asio::buffer(receiveFile->GetData(), receiveFileSize), ReceivedBinder(this));
}

void AsioTcpSocket::Received(const boost::system::error_code& error, size_t transferred)
{
	ptr<ReceiveHandler> receiveHandler;
	ptr<File> receiveFile;

	{
		CriticalCode cc(cs);

		receiveHandler = this->receiveHandler;
		receiveFile = this->receiveFile;

		if(error)
		{
			CloseNonSynced();
			this->receiveHandler = 0;
			this->receiveFile = 0;
		}
		else
			StartReceiving();
	}

	if(receiveHandler)
	{
		if(error)
		{
			// если корректный конец файла, это не ошибка
			if(error == boost::asio::error::eof)
				receiveHandler->FireData(0);
			else
				receiveHandler->FireError(AsioService::ConvertError(error));
		}
		else
			receiveHandler->FireData(NEW(PartFile(receiveFile, receiveFile->GetData(), transferred)));
	}
}

void AsioTcpSocket::CloseNonSynced()
{
	try
	{
		socket.close();
	}
	catch(boost::system::system_error error)
	{
	}
}

void AsioTcpSocket::Send(ptr<File> file, ptr<SendHandler> sendHandler)
{
	try
	{
		CriticalCode cc(cs);

		// если запланировано закрытие передачи, то больше в очередь добавлять ничего нельзя
		if(sendClosed)
			THROW("Sending closed");

		bool queueWasEmpty = sendQueue.empty();

		// добавить элемент в очередь
		sendQueue.push_back(SendItem(file, sendHandler));

		// сбросить количество переданных данных в первом элементе,
		// если очередь была пуста (то есть первый элемент как раз
		// был добавлен)
		// также, если очередь была пуста, начать отправку
		if(queueWasEmpty)
		{
			firstItemSent = 0;
			StartSending();
		}
	}
	catch(Exception* exception)
	{
		THROW_SECONDARY("Can't send data to Asio TCP socket", exception);
	}
}

void AsioTcpSocket::End()
{
	CriticalCode cc(cs);

	if(!sendClosed)
	{
		sendClosed = true;

		if(sendQueue.empty())
			StartSending();
	}
}

void AsioTcpSocket::SetReceiveHandler(ptr<ReceiveHandler> receiveHandler)
{
	CriticalCode cc(cs);

	bool firstTime = !this->receiveHandler;
	this->receiveHandler = receiveHandler;

	if(firstTime)
		// запустить приём
		StartReceiving();
}

void AsioTcpSocket::Close()
{
	CriticalCode cc(cs);

	CloseNonSynced();
}

END_INANITY_NET
<|endoftext|>


<commit_before><commit_msg>Fix typo<commit_after><|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/dom/DOMException.hpp>
#include <xercesc/dom/DOMNode.hpp>

#include "DOMDocumentImpl.hpp"
#include "DOMNodeListImpl.hpp"
#include "DOMRangeImpl.hpp"
#include "DOMParentNode.hpp"
#include "DOMCasts.hpp"

DOMParentNode::DOMParentNode(DOMDocument *ownerDoc)
    : fOwnerDocument(ownerDoc), fChildNodeList(castToNode(this))
{
    fFirstChild = 0;
};

// This only makes a shallow copy, cloneChildren must also be called for a
// deep clone
DOMParentNode::DOMParentNode(const DOMParentNode &other)  :
    fChildNodeList(castToNode(this))
{
    this->fOwnerDocument = other.fOwnerDocument;

    // Need to break the association w/ original kids
    this->fFirstChild = 0;
};

void DOMParentNode::changed()
{
    DOMDocumentImpl *doc = (DOMDocumentImpl *)(castToNodeImpl(this)->getOwnerDocument());
    doc->changed();
}

int DOMParentNode::changes() const
{
    DOMDocumentImpl *doc = (DOMDocumentImpl *)(castToNodeImpl(this)->getOwnerDocument());
    return doc->changes();
};

DOMNode * DOMParentNode::appendChild(DOMNode *newChild)
{
    return insertBefore(newChild, 0);
};

void DOMParentNode::cloneChildren(const DOMNode *other) {
  //    for (DOMNode *mykid = other.getFirstChild();
    for (DOMNode *mykid = other->getFirstChild();
         mykid != 0;
         mykid = mykid->getNextSibling())
    {
        appendChild(mykid->cloneNode(true));
    }
}

DOMDocument * DOMParentNode::getOwnerDocument() const {
    return fOwnerDocument;
}

// unlike getOwnerDocument this is not overriden by DocumentImpl to return 0
DOMDocument * DOMParentNode::getDocument() const {
    return fOwnerDocument;
}

void DOMParentNode::setOwnerDocument(DOMDocument* doc) {
    fOwnerDocument = doc;
}

DOMNodeList *DOMParentNode::getChildNodes() const {
    const DOMNodeList *ret = &fChildNodeList;
    return (DOMNodeList *)ret;   // cast off const.
};

DOMNode * DOMParentNode::getFirstChild() const {
    return fFirstChild;
};

DOMNode * DOMParentNode::getLastChild() const
{
    return lastChild();
};

DOMNode * DOMParentNode::lastChild() const
{
    // last child is stored as the previous sibling of first child
    if (fFirstChild == 0) {
        return 0;
    }

    DOMChildNode *firstChild = castToChildImpl(fFirstChild);
    DOMNode *ret = firstChild->previousSibling;
    return ret;
};

//
//  revisit.  Is this function used anywhere?  I don't see it.
//
void DOMParentNode::lastChild(DOMNode *node) {
    // store lastChild as previous sibling of first child
    if (fFirstChild != 0) {
        DOMChildNode *firstChild = castToChildImpl(fFirstChild);
        firstChild->previousSibling = node;
    }
}

bool DOMParentNode::hasChildNodes() const
{
    return fFirstChild!=0;
};

DOMNode *DOMParentNode::insertBefore(DOMNode *newChild, DOMNode *refChild) {
    DOMNodeImpl *thisNodeImpl = castToNodeImpl(this);
    if (thisNodeImpl->isReadOnly())
        throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);

    if (newChild->getOwnerDocument() != fOwnerDocument)
        throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0);

    // Prevent cycles in the tree
    bool treeSafe=true;
    for(DOMNode *a=castToNode(this)->getParentNode();
        treeSafe && a!=0;
        a=a->getParentNode())
        treeSafe=(newChild!=a);
    if(!treeSafe)
        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);

    // refChild must in fact be a child of this node (or 0)
    if (refChild!=0 && refChild->getParentNode() != castToNode(this))
        throw DOMException(DOMException::NOT_FOUND_ERR,0);

    if (newChild->getNodeType() == DOMNode::DOCUMENT_FRAGMENT_NODE)
    {
        // SLOW BUT SAFE: We could insert the whole subtree without
        // juggling so many next/previous pointers. (Wipe out the
        // parent's child-list, patch the parent pointers, set the
        // ends of the list.) But we know some subclasses have special-
        // case behavior they add to insertBefore(), so we don't risk it.
        // This approch also takes fewer bytecodes.

        // NOTE: If one of the children is not a legal child of this
        // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children
        // have been transferred. (Alternative behaviors would be to
        // reparent up to the first failure point or reparent all those
        // which are acceptable to the target node, neither of which is
        // as robust. PR-DOM-0818 isn't entirely clear on which it
        // recommends?????

        // No need to check kids for right-document; if they weren't,
        // they wouldn't be kids of that DocFrag.
        for(DOMNode *kid=newChild->getFirstChild(); // Prescan
              kid!=0;
              kid=kid->getNextSibling())
        {
            if (!DOMDocumentImpl::isKidOK(castToNode(this), kid))
              throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);
        }
        while(newChild->hasChildNodes())     // Move
            insertBefore(newChild->getFirstChild(),refChild);
    }

    else if (!DOMDocumentImpl::isKidOK(castToNode(this), newChild))
        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);

    else
    {
        DOMNode *oldparent=newChild->getParentNode();
        if(oldparent!=0)
            oldparent->removeChild(newChild);

        // Attach up
        castToNodeImpl(newChild)->fOwnerNode = castToNode(this);
        castToNodeImpl(newChild)->isOwned(true);

        // Attach before and after
        // Note: fFirstChild.previousSibling == lastChild!!
        if (fFirstChild == 0) {
            // this our first and only child
            fFirstChild = newChild;
            castToNodeImpl(newChild)->isFirstChild(true);
            // castToChildImpl(newChild)->previousSibling = newChild;
            DOMChildNode *newChild_ci = castToChildImpl(newChild);
            newChild_ci->previousSibling = newChild;
        } else {
            if (refChild == 0) {
                // this is an append
                DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling;
                castToChildImpl(lastChild)->nextSibling = newChild;
                castToChildImpl(newChild)->previousSibling = lastChild;
                castToChildImpl(fFirstChild)->previousSibling = newChild;
            } else {
                // this is an insert
                if (refChild == fFirstChild) {
                    // at the head of the list
                    castToNodeImpl(fFirstChild)->isFirstChild(false);
                    castToChildImpl(newChild)->nextSibling = fFirstChild;
                    castToChildImpl(newChild)->previousSibling = castToChildImpl(fFirstChild)->previousSibling;
                    castToChildImpl(fFirstChild)->previousSibling = newChild;
                    fFirstChild = newChild;
                    castToNodeImpl(newChild)->isFirstChild(true);
                } else {
                    // somewhere in the middle
                    DOMNode *prev = castToChildImpl(refChild)->previousSibling;
                    castToChildImpl(newChild)->nextSibling = refChild;
                    castToChildImpl(prev)->nextSibling = newChild;
                    castToChildImpl(refChild)->previousSibling = newChild;
                    castToChildImpl(newChild)->previousSibling = prev;
                }
            }
        }
    }

    changed();

    if (this->getOwnerDocument() != 0) {
        Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges();
        if ( ranges != 0) {
            XMLSize_t sz = ranges->size();
            if (sz != 0) {
                for (XMLSize_t i =0; i<sz; i++) {
                    ranges->elementAt(i)->updateRangeForInsertedNode(newChild);
                }
            }
        }
    }

    return newChild;
};

DOMNode *DOMParentNode::removeChild(DOMNode *oldChild)
{
    if (castToNodeImpl(this)->isReadOnly())
        throw DOMException(
        DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);

    if (oldChild != 0 && oldChild->getParentNode() != castToNode(this))
        throw DOMException(DOMException::NOT_FOUND_ERR, 0);

    //fix other ranges for change before deleting the node
    if (this->getOwnerDocument() !=  0  ) {
        Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges();
        if (ranges != 0) {
            XMLSize_t sz = ranges->size();
            if (sz != 0) {
                for (XMLSize_t i =0; i<sz; i++) {
                    if (ranges->elementAt(i) != 0)
                        ranges->elementAt(i)->updateRangeForDeletedNode(oldChild);
                }
            }
        }
    }

    // Patch linked list around oldChild
    // Note: lastChild == fFirstChild->previousSibling
    if (oldChild == fFirstChild) {
        // removing first child
        castToNodeImpl(oldChild)->isFirstChild(false);
        fFirstChild = castToChildImpl(oldChild)->nextSibling;
        if (fFirstChild != 0) {
            castToNodeImpl(fFirstChild)->isFirstChild(true);
            castToChildImpl(fFirstChild)->previousSibling = castToChildImpl(oldChild)->previousSibling;
        }
    } else {
        DOMNode *prev = castToChildImpl(oldChild)->previousSibling;
        DOMNode *next = castToChildImpl(oldChild)->nextSibling;
        castToChildImpl(prev)->nextSibling = next;
        if (next == 0) {
            // removing last child
            castToChildImpl(fFirstChild)->previousSibling = prev;
        } else {
            // removing some other child in the middle
            castToChildImpl(next)->previousSibling = prev;
        }
    }

    // Remove oldChild's references to tree
    castToNodeImpl(oldChild)->fOwnerNode = fOwnerDocument;
    castToNodeImpl(oldChild)->isOwned(false);
    castToChildImpl(oldChild)->nextSibling = 0;
    castToChildImpl(oldChild)->previousSibling = 0;

    changed();

    return oldChild;
};

DOMNode *DOMParentNode::replaceChild(DOMNode *newChild, DOMNode *oldChild)
{
    insertBefore(newChild, oldChild);
    // changed() already done.
    return removeChild(oldChild);
};

//Introduced in DOM Level 2

void DOMParentNode::normalize()
{
    DOMNode *kid, *next;
    for (kid = fFirstChild; kid != 0; kid = next)
    {
        next = castToChildImpl(kid)->nextSibling;

        // If kid and next are both Text nodes (but _not_ CDATASection,
        // which is a subclass of Text), they can be merged.
        if (next != 0 &&
            kid->getNodeType() == DOMNode::TEXT_NODE   &&
            next->getNodeType() == DOMNode::TEXT_NODE )
        {
            ((DOMTextImpl *) kid)->appendData(((DOMTextImpl *) next)->getData());
            // revisit:
            //   should I release the removed node?
            //   not released in case user still referencing it externally
            removeChild(next);
            next = kid; // Don't advance; there might be another.
        }

        // Otherwise it might be an Element, which is handled recursively
        else
            if (kid->getNodeType() == DOMNode::ELEMENT_NODE)
                kid->normalize();
    };

    // changed() will have occurred when the removeChild() was done,
    // so does not have to be reissued.
};

//Introduced in DOM Level 3

bool DOMParentNode::isEqualNode(const DOMNode* arg)
{
    if (castToNodeImpl(this)->isEqualNode(arg))
    {
        DOMNode *kid, *argKid;
        for (kid = fFirstChild, argKid = arg->getFirstChild();
             kid != 0 && argKid != 0;
             kid = kid->getNextSibling(), argKid = argKid->getNextSibling())
        {
            if (!kid->isEqualNode(argKid))
                return false;
        }
        return true;
    }
    return false;
}

//Non-standard extension
void DOMParentNode::release()
{
    DOMNode *kid, *next;
    for (kid = fFirstChild; kid != 0; kid = next)
    {
        next = castToChildImpl(kid)->nextSibling;

        // set is Owned false before releasing its child
        castToNodeImpl(kid)->isToBeReleased(true);
        kid->release();
    }
}

<commit_msg>isEqualNode:     - check for NULL value.     - if children length is not the same -> return false.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 2001, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/dom/DOMException.hpp>
#include <xercesc/dom/DOMNode.hpp>

#include "DOMDocumentImpl.hpp"
#include "DOMNodeListImpl.hpp"
#include "DOMRangeImpl.hpp"
#include "DOMParentNode.hpp"
#include "DOMCasts.hpp"

DOMParentNode::DOMParentNode(DOMDocument *ownerDoc)
    : fOwnerDocument(ownerDoc), fChildNodeList(castToNode(this))
{
    fFirstChild = 0;
};

// This only makes a shallow copy, cloneChildren must also be called for a
// deep clone
DOMParentNode::DOMParentNode(const DOMParentNode &other)  :
    fChildNodeList(castToNode(this))
{
    this->fOwnerDocument = other.fOwnerDocument;

    // Need to break the association w/ original kids
    this->fFirstChild = 0;
};

void DOMParentNode::changed()
{
    DOMDocumentImpl *doc = (DOMDocumentImpl *)(castToNodeImpl(this)->getOwnerDocument());
    doc->changed();
}

int DOMParentNode::changes() const
{
    DOMDocumentImpl *doc = (DOMDocumentImpl *)(castToNodeImpl(this)->getOwnerDocument());
    return doc->changes();
};

DOMNode * DOMParentNode::appendChild(DOMNode *newChild)
{
    return insertBefore(newChild, 0);
};

void DOMParentNode::cloneChildren(const DOMNode *other) {
  //    for (DOMNode *mykid = other.getFirstChild();
    for (DOMNode *mykid = other->getFirstChild();
         mykid != 0;
         mykid = mykid->getNextSibling())
    {
        appendChild(mykid->cloneNode(true));
    }
}

DOMDocument * DOMParentNode::getOwnerDocument() const {
    return fOwnerDocument;
}

// unlike getOwnerDocument this is not overriden by DocumentImpl to return 0
DOMDocument * DOMParentNode::getDocument() const {
    return fOwnerDocument;
}

void DOMParentNode::setOwnerDocument(DOMDocument* doc) {
    fOwnerDocument = doc;
}

DOMNodeList *DOMParentNode::getChildNodes() const {
    const DOMNodeList *ret = &fChildNodeList;
    return (DOMNodeList *)ret;   // cast off const.
};

DOMNode * DOMParentNode::getFirstChild() const {
    return fFirstChild;
};

DOMNode * DOMParentNode::getLastChild() const
{
    return lastChild();
};

DOMNode * DOMParentNode::lastChild() const
{
    // last child is stored as the previous sibling of first child
    if (fFirstChild == 0) {
        return 0;
    }

    DOMChildNode *firstChild = castToChildImpl(fFirstChild);
    DOMNode *ret = firstChild->previousSibling;
    return ret;
};

//
//  revisit.  Is this function used anywhere?  I don't see it.
//
void DOMParentNode::lastChild(DOMNode *node) {
    // store lastChild as previous sibling of first child
    if (fFirstChild != 0) {
        DOMChildNode *firstChild = castToChildImpl(fFirstChild);
        firstChild->previousSibling = node;
    }
}

bool DOMParentNode::hasChildNodes() const
{
    return fFirstChild!=0;
};

DOMNode *DOMParentNode::insertBefore(DOMNode *newChild, DOMNode *refChild) {
    DOMNodeImpl *thisNodeImpl = castToNodeImpl(this);
    if (thisNodeImpl->isReadOnly())
        throw DOMException(DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);

    if (newChild->getOwnerDocument() != fOwnerDocument)
        throw DOMException(DOMException::WRONG_DOCUMENT_ERR, 0);

    // Prevent cycles in the tree
    bool treeSafe=true;
    for(DOMNode *a=castToNode(this)->getParentNode();
        treeSafe && a!=0;
        a=a->getParentNode())
        treeSafe=(newChild!=a);
    if(!treeSafe)
        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);

    // refChild must in fact be a child of this node (or 0)
    if (refChild!=0 && refChild->getParentNode() != castToNode(this))
        throw DOMException(DOMException::NOT_FOUND_ERR,0);

    if (newChild->getNodeType() == DOMNode::DOCUMENT_FRAGMENT_NODE)
    {
        // SLOW BUT SAFE: We could insert the whole subtree without
        // juggling so many next/previous pointers. (Wipe out the
        // parent's child-list, patch the parent pointers, set the
        // ends of the list.) But we know some subclasses have special-
        // case behavior they add to insertBefore(), so we don't risk it.
        // This approch also takes fewer bytecodes.

        // NOTE: If one of the children is not a legal child of this
        // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children
        // have been transferred. (Alternative behaviors would be to
        // reparent up to the first failure point or reparent all those
        // which are acceptable to the target node, neither of which is
        // as robust. PR-DOM-0818 isn't entirely clear on which it
        // recommends?????

        // No need to check kids for right-document; if they weren't,
        // they wouldn't be kids of that DocFrag.
        for(DOMNode *kid=newChild->getFirstChild(); // Prescan
              kid!=0;
              kid=kid->getNextSibling())
        {
            if (!DOMDocumentImpl::isKidOK(castToNode(this), kid))
              throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);
        }
        while(newChild->hasChildNodes())     // Move
            insertBefore(newChild->getFirstChild(),refChild);
    }

    else if (!DOMDocumentImpl::isKidOK(castToNode(this), newChild))
        throw DOMException(DOMException::HIERARCHY_REQUEST_ERR,0);

    else
    {
        DOMNode *oldparent=newChild->getParentNode();
        if(oldparent!=0)
            oldparent->removeChild(newChild);

        // Attach up
        castToNodeImpl(newChild)->fOwnerNode = castToNode(this);
        castToNodeImpl(newChild)->isOwned(true);

        // Attach before and after
        // Note: fFirstChild.previousSibling == lastChild!!
        if (fFirstChild == 0) {
            // this our first and only child
            fFirstChild = newChild;
            castToNodeImpl(newChild)->isFirstChild(true);
            // castToChildImpl(newChild)->previousSibling = newChild;
            DOMChildNode *newChild_ci = castToChildImpl(newChild);
            newChild_ci->previousSibling = newChild;
        } else {
            if (refChild == 0) {
                // this is an append
                DOMNode *lastChild = castToChildImpl(fFirstChild)->previousSibling;
                castToChildImpl(lastChild)->nextSibling = newChild;
                castToChildImpl(newChild)->previousSibling = lastChild;
                castToChildImpl(fFirstChild)->previousSibling = newChild;
            } else {
                // this is an insert
                if (refChild == fFirstChild) {
                    // at the head of the list
                    castToNodeImpl(fFirstChild)->isFirstChild(false);
                    castToChildImpl(newChild)->nextSibling = fFirstChild;
                    castToChildImpl(newChild)->previousSibling = castToChildImpl(fFirstChild)->previousSibling;
                    castToChildImpl(fFirstChild)->previousSibling = newChild;
                    fFirstChild = newChild;
                    castToNodeImpl(newChild)->isFirstChild(true);
                } else {
                    // somewhere in the middle
                    DOMNode *prev = castToChildImpl(refChild)->previousSibling;
                    castToChildImpl(newChild)->nextSibling = refChild;
                    castToChildImpl(prev)->nextSibling = newChild;
                    castToChildImpl(refChild)->previousSibling = newChild;
                    castToChildImpl(newChild)->previousSibling = prev;
                }
            }
        }
    }

    changed();

    if (this->getOwnerDocument() != 0) {
        Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges();
        if ( ranges != 0) {
            XMLSize_t sz = ranges->size();
            if (sz != 0) {
                for (XMLSize_t i =0; i<sz; i++) {
                    ranges->elementAt(i)->updateRangeForInsertedNode(newChild);
                }
            }
        }
    }

    return newChild;
};

DOMNode *DOMParentNode::removeChild(DOMNode *oldChild)
{
    if (castToNodeImpl(this)->isReadOnly())
        throw DOMException(
        DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);

    if (oldChild != 0 && oldChild->getParentNode() != castToNode(this))
        throw DOMException(DOMException::NOT_FOUND_ERR, 0);

    //fix other ranges for change before deleting the node
    if (this->getOwnerDocument() !=  0  ) {
        Ranges* ranges = ((DOMDocumentImpl *)this->getOwnerDocument())->getRanges();
        if (ranges != 0) {
            XMLSize_t sz = ranges->size();
            if (sz != 0) {
                for (XMLSize_t i =0; i<sz; i++) {
                    if (ranges->elementAt(i) != 0)
                        ranges->elementAt(i)->updateRangeForDeletedNode(oldChild);
                }
            }
        }
    }

    // Patch linked list around oldChild
    // Note: lastChild == fFirstChild->previousSibling
    if (oldChild == fFirstChild) {
        // removing first child
        castToNodeImpl(oldChild)->isFirstChild(false);
        fFirstChild = castToChildImpl(oldChild)->nextSibling;
        if (fFirstChild != 0) {
            castToNodeImpl(fFirstChild)->isFirstChild(true);
            castToChildImpl(fFirstChild)->previousSibling = castToChildImpl(oldChild)->previousSibling;
        }
    } else {
        DOMNode *prev = castToChildImpl(oldChild)->previousSibling;
        DOMNode *next = castToChildImpl(oldChild)->nextSibling;
        castToChildImpl(prev)->nextSibling = next;
        if (next == 0) {
            // removing last child
            castToChildImpl(fFirstChild)->previousSibling = prev;
        } else {
            // removing some other child in the middle
            castToChildImpl(next)->previousSibling = prev;
        }
    }

    // Remove oldChild's references to tree
    castToNodeImpl(oldChild)->fOwnerNode = fOwnerDocument;
    castToNodeImpl(oldChild)->isOwned(false);
    castToChildImpl(oldChild)->nextSibling = 0;
    castToChildImpl(oldChild)->previousSibling = 0;

    changed();

    return oldChild;
};

DOMNode *DOMParentNode::replaceChild(DOMNode *newChild, DOMNode *oldChild)
{
    insertBefore(newChild, oldChild);
    // changed() already done.
    return removeChild(oldChild);
};

//Introduced in DOM Level 2

void DOMParentNode::normalize()
{
    DOMNode *kid, *next;
    for (kid = fFirstChild; kid != 0; kid = next)
    {
        next = castToChildImpl(kid)->nextSibling;

        // If kid and next are both Text nodes (but _not_ CDATASection,
        // which is a subclass of Text), they can be merged.
        if (next != 0 &&
            kid->getNodeType() == DOMNode::TEXT_NODE   &&
            next->getNodeType() == DOMNode::TEXT_NODE )
        {
            ((DOMTextImpl *) kid)->appendData(((DOMTextImpl *) next)->getData());
            // revisit:
            //   should I release the removed node?
            //   not released in case user still referencing it externally
            removeChild(next);
            next = kid; // Don't advance; there might be another.
        }

        // Otherwise it might be an Element, which is handled recursively
        else
            if (kid->getNodeType() == DOMNode::ELEMENT_NODE)
                kid->normalize();
    };

    // changed() will have occurred when the removeChild() was done,
    // so does not have to be reissued.
};

//Introduced in DOM Level 3

bool DOMParentNode::isEqualNode(const DOMNode* arg)
{
    if (arg && castToNodeImpl(this)->isEqualNode(arg))
    {
        DOMNode *kid, *argKid;
        for (kid = fFirstChild, argKid = arg->getFirstChild();
             kid != 0 && argKid != 0;
             kid = kid->getNextSibling(), argKid = argKid->getNextSibling())
        {
            if (!kid->isEqualNode(argKid))
                return false;
        }
        return (kid || argKid) ? false : true;
    }
    return false;
}

//Non-standard extension
void DOMParentNode::release()
{
    DOMNode *kid, *next;
    for (kid = fFirstChild; kid != 0; kid = next)
    {
        next = castToChildImpl(kid)->nextSibling;

        // set is Owned false before releasing its child
        castToNodeImpl(kid)->isToBeReleased(true);
        kid->release();
    }
}

<|endoftext|>


<commit_before>
#include "HelloTriangleApplication.hpp"

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vulkan/vulkan.hpp>

#include <algorithm>

// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
struct HelloTriangleApplication::WindowHandler
{
  GLFWwindow* window;

  WindowHandler() : window{nullptr}
  {
    glfwInit();

    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

    window = glfwCreateWindow(HelloTriangleApplication::k_width,
        HelloTriangleApplication::k_height, "Vulkan", nullptr, nullptr);
  }

  ~WindowHandler()
  {
    glfwDestroyWindow(window);
    glfwTerminate();
  }
};

HelloTriangleApplication::HelloTriangleApplication()
    : window_handler_{new WindowHandler{}}, vk_instance_{nullptr}
{
}

HelloTriangleApplication::~HelloTriangleApplication() = default;

void HelloTriangleApplication::run()
{
  initVulkan();
  mainLoop();
}

void HelloTriangleApplication::initVulkan()
{
  createInstance();
}

void HelloTriangleApplication::mainLoop()
{
  while (!glfwWindowShouldClose(window_handler_->window)) {
    glfwPollEvents();
  }
}

std::vector<const char*> getExtensions()
{
  uint32_t glfw_extension_count{};
  const char** glfw_extensions =
      glfwGetRequiredInstanceExtensions(&glfw_extension_count);

  std::vector<const char*> extensions(glfw_extension_count);
  std::copy_n(glfw_extensions, glfw_extension_count, std::begin(extensions));

  return extensions;
}

void HelloTriangleApplication::createInstance()
{
  vk::ApplicationInfo app_info{
      "Hello Triangle",         // pApplicationName
      VK_MAKE_VERSION(1, 0, 0), // application version
      "No Engine",              //
      VK_MAKE_VERSION(1, 0, 0), // engine version
      VK_API_VERSION_1_0        //
  };

  auto extensions = getExtensions();

  vk::InstanceCreateInfo create_info{{}, &app_info, 0, {},
      static_cast<uint32_t>(extensions.size()), extensions.data()};

  vk_instance_ = vk::createInstanceUnique(create_info);
}

// vim:set et ts=2 sw=0 sts=0:

<commit_msg>Remove unnecessary qualifier from parameters<commit_after>
#include "HelloTriangleApplication.hpp"

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vulkan/vulkan.hpp>

#include <algorithm>

// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
struct HelloTriangleApplication::WindowHandler
{
  GLFWwindow* window;

  WindowHandler() : window{nullptr}
  {
    glfwInit();

    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

    window = glfwCreateWindow(k_width, k_height, "Vulkan", nullptr, nullptr);
  }

  ~WindowHandler()
  {
    glfwDestroyWindow(window);
    glfwTerminate();
  }
};

HelloTriangleApplication::HelloTriangleApplication()
    : window_handler_{new WindowHandler{}}, vk_instance_{nullptr}
{
}

HelloTriangleApplication::~HelloTriangleApplication() = default;

void HelloTriangleApplication::run()
{
  initVulkan();
  mainLoop();
}

void HelloTriangleApplication::initVulkan()
{
  createInstance();
}

void HelloTriangleApplication::mainLoop()
{
  while (!glfwWindowShouldClose(window_handler_->window)) {
    glfwPollEvents();
  }
}

std::vector<const char*> getExtensions()
{
  uint32_t glfw_extension_count{};
  const char** glfw_extensions =
      glfwGetRequiredInstanceExtensions(&glfw_extension_count);

  std::vector<const char*> extensions(glfw_extension_count);
  std::copy_n(glfw_extensions, glfw_extension_count, std::begin(extensions));

  return extensions;
}

void HelloTriangleApplication::createInstance()
{
  vk::ApplicationInfo app_info{
      "Hello Triangle",         // pApplicationName
      VK_MAKE_VERSION(1, 0, 0), // application version
      "No Engine",              //
      VK_MAKE_VERSION(1, 0, 0), // engine version
      VK_API_VERSION_1_0        //
  };

  auto extensions = getExtensions();

  vk::InstanceCreateInfo create_info{{}, &app_info, 0, {},
      static_cast<uint32_t>(extensions.size()), extensions.data()};

  vk_instance_ = vk::createInstanceUnique(create_info);
}

// vim:set et ts=2 sw=0 sts=0:

<|endoftext|>


<commit_before>#include "cache.hxx"
#include "pool.hxx"
#include "RootPool.hxx"
#include "event/Event.hxx"

#include <assert.h>
#include <time.h>

static void *
match_to_ptr(int match)
{
    return (void*)(long)match;
}

static int
ptr_to_match(void *p)
{
    return (int)(long)p;
}

struct MyCacheItem {
    CacheItem item;

    struct pool *const pool;
    const int match;
    const int value;

    MyCacheItem(struct pool &_pool, int _match, int _value)
        :item(std::chrono::hours(1), 1),
         pool(&_pool), match(_match), value(_value) {
    }
};

static bool
my_cache_validate(CacheItem *item)
{
    auto *i = (MyCacheItem *)item;

    (void)i;
    return true;
}

static void
my_cache_destroy(CacheItem *item)
{
    auto *i = (MyCacheItem *)item;
    struct pool *pool = i->pool;

    p_free(pool, i);
    pool_unref(pool);
}

static constexpr CacheClass my_cache_class = {
    .validate = my_cache_validate,
    .destroy = my_cache_destroy,
};

static MyCacheItem *
my_cache_item_new(struct pool *pool, int match, int value)
{
    pool = pool_new_linear(pool, "my_cache_item", 1024);
    auto i = NewFromPool<MyCacheItem>(*pool, *pool, match, value);
    return i;
}

static bool
my_match(const CacheItem *item, void *ctx)
{
    const MyCacheItem *i = (const MyCacheItem *)item;
    int match = ptr_to_match(ctx);

    return i->match == match;
}

int main(int argc gcc_unused, char **argv gcc_unused) {
    MyCacheItem *i;

    EventLoop event_loop;

    RootPool pool;

    Cache *cache = cache_new(*pool, event_loop, my_cache_class, 1024, 4);

    /* add first item */

    i = my_cache_item_new(pool, 1, 0);
    cache_put(cache, "foo", &i->item);

    /* overwrite first item */

    i = my_cache_item_new(pool, 2, 0);
    cache_put(cache, "foo", &i->item);

    /* check overwrite result */

    i = (MyCacheItem *)cache_get(cache, "foo");
    assert(i != nullptr);
    assert(i->match == 2);
    assert(i->value == 0);

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(1));
    assert(i == nullptr);

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(2));
    assert(i != nullptr);
    assert(i->match == 2);
    assert(i->value == 0);

    /* add new item */

    i = my_cache_item_new(pool, 1, 1);
    cache_put_match(cache, "foo", &i->item, my_match, match_to_ptr(1));

    /* check second item */

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(1));
    assert(i != nullptr);
    assert(i->match == 1);
    assert(i->value == 1);

    /* check first item */

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(2));
    assert(i != nullptr);
    assert(i->match == 2);
    assert(i->value == 0);

    /* overwrite first item */

    i = my_cache_item_new(pool, 1, 3);
    cache_put_match(cache, "foo", &i->item, my_match, match_to_ptr(1));

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(1));
    assert(i != nullptr);
    assert(i->match == 1);
    assert(i->value == 3);

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(2));
    assert(i != nullptr);
    assert(i->match == 2);
    assert(i->value == 0);

    /* overwrite second item */

    i = my_cache_item_new(pool, 2, 4);
    cache_put_match(cache, "foo", &i->item, my_match, match_to_ptr(2));

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(1));
    assert(i != nullptr);
    assert(i->match == 1);
    assert(i->value == 3);

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(2));
    assert(i != nullptr);
    assert(i->match == 2);
    assert(i->value == 4);

    /* cleanup */

    cache_close(cache);
}
<commit_msg>test/t_cache: use CacheItem as base class<commit_after>#include "cache.hxx"
#include "pool.hxx"
#include "RootPool.hxx"
#include "event/Event.hxx"

#include <assert.h>
#include <time.h>

static void *
match_to_ptr(int match)
{
    return (void*)(long)match;
}

static int
ptr_to_match(void *p)
{
    return (int)(long)p;
}

struct MyCacheItem final : CacheItem {
    struct pool *const pool;
    const int match;
    const int value;

    MyCacheItem(struct pool &_pool, int _match, int _value)
        :CacheItem(std::chrono::hours(1), 1),
         pool(&_pool), match(_match), value(_value) {
    }
};

static bool
my_cache_validate(CacheItem *item)
{
    auto *i = (MyCacheItem *)item;

    (void)i;
    return true;
}

static void
my_cache_destroy(CacheItem *item)
{
    auto *i = (MyCacheItem *)item;
    struct pool *pool = i->pool;

    p_free(pool, i);
    pool_unref(pool);
}

static constexpr CacheClass my_cache_class = {
    .validate = my_cache_validate,
    .destroy = my_cache_destroy,
};

static MyCacheItem *
my_cache_item_new(struct pool *pool, int match, int value)
{
    pool = pool_new_linear(pool, "my_cache_item", 1024);
    auto i = NewFromPool<MyCacheItem>(*pool, *pool, match, value);
    return i;
}

static bool
my_match(const CacheItem *item, void *ctx)
{
    const MyCacheItem *i = (const MyCacheItem *)item;
    int match = ptr_to_match(ctx);

    return i->match == match;
}

int main(int argc gcc_unused, char **argv gcc_unused) {
    MyCacheItem *i;

    EventLoop event_loop;

    RootPool pool;

    Cache *cache = cache_new(*pool, event_loop, my_cache_class, 1024, 4);

    /* add first item */

    i = my_cache_item_new(pool, 1, 0);
    cache_put(cache, "foo", i);

    /* overwrite first item */

    i = my_cache_item_new(pool, 2, 0);
    cache_put(cache, "foo", i);

    /* check overwrite result */

    i = (MyCacheItem *)cache_get(cache, "foo");
    assert(i != nullptr);
    assert(i->match == 2);
    assert(i->value == 0);

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(1));
    assert(i == nullptr);

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(2));
    assert(i != nullptr);
    assert(i->match == 2);
    assert(i->value == 0);

    /* add new item */

    i = my_cache_item_new(pool, 1, 1);
    cache_put_match(cache, "foo", i, my_match, match_to_ptr(1));

    /* check second item */

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(1));
    assert(i != nullptr);
    assert(i->match == 1);
    assert(i->value == 1);

    /* check first item */

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(2));
    assert(i != nullptr);
    assert(i->match == 2);
    assert(i->value == 0);

    /* overwrite first item */

    i = my_cache_item_new(pool, 1, 3);
    cache_put_match(cache, "foo", i, my_match, match_to_ptr(1));

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(1));
    assert(i != nullptr);
    assert(i->match == 1);
    assert(i->value == 3);

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(2));
    assert(i != nullptr);
    assert(i->match == 2);
    assert(i->value == 0);

    /* overwrite second item */

    i = my_cache_item_new(pool, 2, 4);
    cache_put_match(cache, "foo", i, my_match, match_to_ptr(2));

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(1));
    assert(i != nullptr);
    assert(i->match == 1);
    assert(i->value == 3);

    i = (MyCacheItem *)cache_get_match(cache, "foo",
                                                my_match, match_to_ptr(2));
    assert(i != nullptr);
    assert(i->match == 2);
    assert(i->value == 4);

    /* cleanup */

    cache_close(cache);
}
<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "Step8.h"

#include "QmitkStdMultiWidget.h"

#include "mitkGlobalInteraction.h"
#include "mitkRenderingManager.h"
#include <mitkImageVtkMapper2D.h>

#include <QHBoxLayout>
#include <QVBoxLayout>

#include <vtkInteractorStyle.h>
#include <vtkInteractorStyleImage.h>

//##Documentation
//## @brief As Step6, but with QmitkStdMultiWidget as widget
Step8::Step8(int argc, char* argv[], QWidget *parent) :
	Step6(argc, argv, parent)
{
}

void Step8::SetupWidgets()
{
	//*************************************************************************
	// Part I: Create windows and pass the tree to it
	//*************************************************************************

	// Create toplevel widget with vertical layout
	QVBoxLayout* vlayout = new QVBoxLayout(this);
	vlayout->setMargin(0);
	vlayout->setSpacing(2);

	// Create viewParent widget with horizontal layout
	QWidget* viewParent = new QWidget(this);
	vlayout->addWidget(viewParent);
	QHBoxLayout* hlayout = new QHBoxLayout(viewParent);
	hlayout->setMargin(0);

	mitk::ImageVtkMapper2D::Pointer mapper = mitk::ImageVtkMapper2D::New();
	m_ResultNode->SetMapper(mitk::BaseRenderer::Extended2D, mapper);

	//*************************************************************************
	// Part Ia: create and initialize QmitkStdMultiWidget
	//*************************************************************************
	QmitkStdMultiWidget* multiWidget = new QmitkStdMultiWidget(viewParent);

	hlayout->addWidget(multiWidget);

	// Tell the multiWidget which DataStorage to render
	multiWidget->SetDataStorage(m_DataStorage);

	// Initialize views as transversal, sagittal, coronar (from
	// top-left to bottom)
	mitk::TimeSlicedGeometry::Pointer geo = m_DataStorage->ComputeBoundingGeometry3D(
			m_DataStorage->GetAll());
	mitk::RenderingManager::GetInstance()->InitializeViews(geo);

	// Setup render window interactor
//  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
//  vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	vtkSmartPointer<vtkInteractorStyleImage> style = vtkSmartPointer<vtkInteractorStyleImage>::New();
//		renderWindowInteractor->SetInteractorStyle(style);

	// Initialize bottom-right view as 3D view
	multiWidget->GetRenderWindow1()->GetRenderer()->SetMapperID(
			mitk::BaseRenderer::Extended2D);
	multiWidget->GetRenderWindow1()->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style);
//	renderWindowInteractor->Start();

	// Enable standard handler for levelwindow-slider
	multiWidget->EnableStandardLevelWindow();

	// Add the displayed views to the DataStorage to see their positions in 2D and 3D
	multiWidget->AddDisplayPlaneSubTree();
	multiWidget->AddPlanesToDataStorage();
	multiWidget->SetWidgetPlanesVisibility(true);

	//*************************************************************************
	// Part II: Setup standard interaction with the mouse
	//*************************************************************************

	// Moving the cut-planes to click-point
	multiWidget->EnableNavigationControllerEventListening();

  mitk::SliceNavigationController::Pointer sliceNavi = multiWidget->GetRenderWindow2()->GetSliceNavigationController();
  sliceNavi->SetViewDirection(mitk::SliceNavigationController::Transversal);
  sliceNavi->Update();

	// Zooming and panning
	mitk::GlobalInteraction::GetInstance()->AddListener(
			multiWidget->GetMoveAndZoomInteractor());
}
/**
 \example Step8.cpp
 */
<commit_msg>3D Interactor aktiviert<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "Step8.h"

#include "QmitkStdMultiWidget.h"

#include "mitkGlobalInteraction.h"
#include "mitkRenderingManager.h"
#include <mitkImageVtkMapper2D.h>

#include <QHBoxLayout>
#include <QVBoxLayout>

#include <vtkInteractorStyle.h>
#include <vtkInteractorStyleImage.h>

//##Documentation
//## @brief As Step6, but with QmitkStdMultiWidget as widget
Step8::Step8(int argc, char* argv[], QWidget *parent) :
	Step6(argc, argv, parent)
{
}

void Step8::SetupWidgets()
{
	//*************************************************************************
	// Part I: Create windows and pass the tree to it
	//*************************************************************************

	// Create toplevel widget with vertical layout
	QVBoxLayout* vlayout = new QVBoxLayout(this);
	vlayout->setMargin(0);
	vlayout->setSpacing(2);

	// Create viewParent widget with horizontal layout
	QWidget* viewParent = new QWidget(this);
	vlayout->addWidget(viewParent);
	QHBoxLayout* hlayout = new QHBoxLayout(viewParent);
	hlayout->setMargin(0);

	mitk::ImageVtkMapper2D::Pointer mapper = mitk::ImageVtkMapper2D::New();
	m_ResultNode->SetMapper(mitk::BaseRenderer::Extended2D, mapper);

	//*************************************************************************
	// Part Ia: create and initialize QmitkStdMultiWidget
	//*************************************************************************
	QmitkStdMultiWidget* multiWidget = new QmitkStdMultiWidget(viewParent);

	hlayout->addWidget(multiWidget);

	// Tell the multiWidget which DataStorage to render
	multiWidget->SetDataStorage(m_DataStorage);

	// Initialize views as transversal, sagittal, coronar (from
	// top-left to bottom)
	mitk::TimeSlicedGeometry::Pointer geo = m_DataStorage->ComputeBoundingGeometry3D(
			m_DataStorage->GetAll());
	mitk::RenderingManager::GetInstance()->InitializeViews(geo);

	// Setup render window interactor
//  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
//  vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
//		renderWindowInteractor->SetInteractorStyle(style);

	// Initialize bottom-right view as 3D view
	multiWidget->GetRenderWindow1()->GetRenderer()->SetMapperID(
			mitk::BaseRenderer::Extended2D);
//	multiWidget->GetRenderWindow1()->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style);
//	renderWindowInteractor->Start();

	// Enable standard handler for levelwindow-slider
	multiWidget->EnableStandardLevelWindow();

	// Add the displayed views to the DataStorage to see their positions in 2D and 3D
	multiWidget->AddDisplayPlaneSubTree();
	multiWidget->AddPlanesToDataStorage();
	multiWidget->SetWidgetPlanesVisibility(true);

	//*************************************************************************
	// Part II: Setup standard interaction with the mouse
	//*************************************************************************

	// Moving the cut-planes to click-point
	multiWidget->EnableNavigationControllerEventListening();

  mitk::SliceNavigationController::Pointer sliceNavi = multiWidget->GetRenderWindow2()->GetSliceNavigationController();
  sliceNavi->SetViewDirection(mitk::SliceNavigationController::Transversal);
  sliceNavi->Update();

	// Zooming and panning
	mitk::GlobalInteraction::GetInstance()->AddListener(
			multiWidget->GetMoveAndZoomInteractor());
}
/**
 \example Step8.cpp
 */
<|endoftext|>


<commit_before>// @(#)root/minuit2:$Id$
// Authors: M. Winkler, F. James, L. Moneta, A. Zsenei   2003-2005

/**********************************************************************
 *                                                                    *
 * Copyright (c) 2005 LCG ROOT Math team,  CERN/PH-SFT                *
 *                                                                    *
 **********************************************************************/

#include "Minuit2/MnContours.h"
#include "Minuit2/MnMinos.h"
#include "Minuit2/MnMigrad.h"
#include "Minuit2/MnFunctionCross.h"
#include "Minuit2/FunctionMinimum.h"
#include "Minuit2/FCNBase.h"
#include "Minuit2/MnCross.h"
#include "Minuit2/MinosError.h"
#include "Minuit2/ContoursError.h"

#include "Minuit2/MnPrint.h"

namespace ROOT {

   namespace Minuit2 {

void PrintContourPoint(const std::pair<double,double> & point)  {
#ifdef WARNINGMSG
#ifdef USE_ROOT_ERROR
   std::string msg = "\tx = " + ROOT::Math::Util::ToString(point.first) + "\ty = " + ROOT::Math::Util::ToString(point.first);
   MN_INFO_MSG2("MnContour",msg.c_str());
#else
   std::cout << " x  = " << point.first << "  y = " << point.second << std::endl;
#endif
#endif
}

std::vector<std::pair<double,double> > MnContours::operator()(unsigned int px, unsigned int py, unsigned int npoints) const {
   // get contour as a pair of (x,y) points passing the parameter index (px, py)  and the number of requested points (>=4)
   ContoursError cont = Contour(px, py, npoints);
   return cont();
}

ContoursError MnContours::Contour(unsigned int px, unsigned int py, unsigned int npoints) const {
   // calculate the contour passing the parameter index (px, py)  and the number of requested points (>=4)
   // the fcn.UP() has to be set to the rquired value (see Minuit document on errors)
   assert(npoints > 3);
   unsigned int maxcalls = 100*(npoints+5)*(fMinimum.UserState().VariableParameters()+1);
   unsigned int nfcn = 0;

   std::vector<std::pair<double,double> > result; result.reserve(npoints);
   std::vector<MnUserParameterState> states;
   //   double edmmax = 0.5*0.05*fFCN.Up()*1.e-3;

   //double toler = 0.05;
   double toler = 0.1; // use same defaut value as in Minos

   //get first four points
   //   std::cout<<"MnContours: get first 4 params."<<std::endl;
   MnMinos minos(fFCN, fMinimum, fStrategy);

   double valx = fMinimum.UserState().Value(px);
   double valy = fMinimum.UserState().Value(py);

   MinosError mex = minos.Minos(px);
   nfcn += mex.NFcn();
   if(!mex.IsValid()) {
      MN_ERROR_MSG("MnContours is unable to find first two points.");
      return ContoursError(px, py, result, mex, mex, nfcn);
   }
   std::pair<double,double> ex = mex();

   MinosError mey = minos.Minos(py);
   nfcn += mey.NFcn();
   if(!mey.IsValid()) {
      MN_ERROR_MSG("MnContours is unable to find second two points.");
      return ContoursError(px, py, result, mex, mey, nfcn);
   }
   std::pair<double,double> ey = mey();

   MnMigrad migrad(fFCN, fMinimum.UserState(), MnStrategy(std::max(0, int(fStrategy.Strategy()-1))));

   migrad.Fix(px);
   migrad.SetValue(px, valx + ex.second);
   FunctionMinimum exy_up = migrad();
   nfcn += exy_up.NFcn();
   if(!exy_up.IsValid()) {
      MN_ERROR_VAL2("MnContours: unable to find Upper y Value for x Parameter",px);
      return ContoursError(px, py, result, mex, mey, nfcn);
   }

   migrad.SetValue(px, valx + ex.first);
   FunctionMinimum exy_lo = migrad();
   nfcn += exy_lo.NFcn();
   if(!exy_lo.IsValid()) {
      MN_ERROR_VAL2("MnContours: unable to find Lower y Value for x Parameter",px);
      return ContoursError(px, py, result, mex, mey, nfcn);
   }

   MnMigrad migrad1(fFCN, fMinimum.UserState(), MnStrategy(std::max(0, int(fStrategy.Strategy()-1))));
   migrad1.Fix(py);
   migrad1.SetValue(py, valy + ey.second);
   FunctionMinimum eyx_up = migrad1();
   nfcn += eyx_up.NFcn();
   if(!eyx_up.IsValid()) {
      MN_ERROR_VAL2("MnContours: unable to find Upper x Value for y Parameter",py);
      return ContoursError(px, py, result, mex, mey, nfcn);
   }

   migrad1.SetValue(py, valy + ey.first);
   FunctionMinimum eyx_lo = migrad1();
   nfcn += eyx_lo.NFcn();
   if(!eyx_lo.IsValid()) {
      MN_ERROR_VAL2("MnContours: unable to find Lower x Value for y Parameter",py);
      return ContoursError(px, py, result, mex, mey, nfcn);
   }

   double scalx = 1./(ex.second - ex.first);
   double scaly = 1./(ey.second - ey.first);

   result.push_back(std::pair<double,double>(valx + ex.first, exy_lo.UserState().Value(py)));
   result.push_back(std::pair<double,double>(eyx_lo.UserState().Value(px), valy + ey.first));
   result.push_back(std::pair<double,double>(valx + ex.second, exy_up.UserState().Value(py)));
   result.push_back(std::pair<double,double>(eyx_up.UserState().Value(px), valy + ey.second));

   //   std::cout<<"MnContours: first 4 params finished."<<std::endl;
#ifdef WARNINGMSG
   MN_INFO_MSG("Minuit2::MnContour : List of  found points");
   MN_INFO_VAL2("Minuit2::MnContour : parameter number x",px);
   MN_INFO_VAL2("Minuit2::MnContour : parameter number y",py);
#endif

   for (unsigned int i = 0; i < 4; ++i)
      PrintContourPoint(result[i] );

   MnUserParameterState upar = fMinimum.UserState();
   upar.Fix(px);
   upar.Fix(py);

   std::vector<unsigned int> par(2); par[0] = px; par[1] = py;
   MnFunctionCross cross(fFCN, upar, fMinimum.Fval(), fStrategy);

   for(unsigned int i = 4; i < npoints; i++) {

      std::vector<std::pair<double,double> >::iterator idist1 = result.end()-1;
      std::vector<std::pair<double,double> >::iterator idist2 = result.begin();
      double dx = idist1->first - (idist2)->first;
      double dy = idist1->second - (idist2)->second;
      double bigdis = scalx*scalx*dx*dx + scaly*scaly*dy*dy;

      for(std::vector<std::pair<double,double> >::iterator ipair = result.begin(); ipair != result.end()-1; ipair++) {
         double distx = ipair->first - (ipair+1)->first;
         double disty = ipair->second - (ipair+1)->second;
         double dist = scalx*scalx*distx*distx + scaly*scaly*disty*disty;
         if(dist > bigdis) {
            bigdis = dist;
            idist1 = ipair;
            idist2 = ipair+1;
         }
      }

      double a1 = 0.5;
      double a2 = 0.5;
      double sca = 1.;

L300:

      if(nfcn > maxcalls) {
         MN_ERROR_MSG("MnContours: maximum number of function calls exhausted.");
         return ContoursError(px, py, result, mex, mey, nfcn);
      }

      double xmidcr = a1*idist1->first + a2*(idist2)->first;
      double ymidcr = a1*idist1->second + a2*(idist2)->second;
      double xdir = (idist2)->second - idist1->second;
      double ydir = idist1->first - (idist2)->first;
      double scalfac = sca*std::max(fabs(xdir*scalx), fabs(ydir*scaly));
      double xdircr = xdir/scalfac;
      double ydircr = ydir/scalfac;
      std::vector<double> pmid(2); pmid[0] = xmidcr; pmid[1] = ymidcr;
      std::vector<double> pdir(2); pdir[0] = xdircr; pdir[1] = ydircr;

      MnCross opt = cross(par, pmid, pdir, toler, maxcalls);
      nfcn += opt.NFcn();
      if(!opt.IsValid()) {
         //       if(a1 > 0.5) {
         if(sca < 0.) {
            MN_ERROR_VAL2("MnContours : unable to find point on Contour",i+1);
            MN_ERROR_VAL2("MnContours : found  only i points",i);
            return ContoursError(px, py, result, mex, mey, nfcn);
         }
         //       a1 = 0.75;
         //       a2 = 0.25;
         //       std::cout<<"*****switch direction"<<std::endl;
         sca = -1.;
         goto L300;
         }
      double aopt = opt.Value();
      if(idist2 == result.begin()) {
         result.push_back(std::pair<double,double>(xmidcr+(aopt)*xdircr, ymidcr + (aopt)*ydircr));
         PrintContourPoint( result.back() );
      }
      else {
         result.insert(idist2, std::pair<double,double>(xmidcr+(aopt)*xdircr, ymidcr + (aopt)*ydircr));
         PrintContourPoint( *idist2 );
      }
   }
   return ContoursError(px, py, result, mex, mey, nfcn);
}

   }  // namespace Minuit2

}  // namespace ROOT
<commit_msg>fix printing message of contour points<commit_after>// @(#)root/minuit2:$Id$
// Authors: M. Winkler, F. James, L. Moneta, A. Zsenei   2003-2005

/**********************************************************************
 *                                                                    *
 * Copyright (c) 2005 LCG ROOT Math team,  CERN/PH-SFT                *
 *                                                                    *
 **********************************************************************/

#include "Minuit2/MnContours.h"
#include "Minuit2/MnMinos.h"
#include "Minuit2/MnMigrad.h"
#include "Minuit2/MnFunctionCross.h"
#include "Minuit2/FunctionMinimum.h"
#include "Minuit2/FCNBase.h"
#include "Minuit2/MnCross.h"
#include "Minuit2/MinosError.h"
#include "Minuit2/ContoursError.h"

#include "Minuit2/MnPrint.h"

namespace ROOT {

   namespace Minuit2 {

void PrintContourPoint(const std::pair<double,double> & point)  {
   std::cout << "\t x  = " << point.first << "  y = " << point.second << std::endl;
}

std::vector<std::pair<double,double> > MnContours::operator()(unsigned int px, unsigned int py, unsigned int npoints) const {
   // get contour as a pair of (x,y) points passing the parameter index (px, py)  and the number of requested points (>=4)
   ContoursError cont = Contour(px, py, npoints);
   return cont();
}

ContoursError MnContours::Contour(unsigned int px, unsigned int py, unsigned int npoints) const {
   // calculate the contour passing the parameter index (px, py)  and the number of requested points (>=4)
   // the fcn.UP() has to be set to the rquired value (see Minuit document on errors)
   assert(npoints > 3);
   unsigned int maxcalls = 100*(npoints+5)*(fMinimum.UserState().VariableParameters()+1);
   unsigned int nfcn = 0;

   std::vector<std::pair<double,double> > result; result.reserve(npoints);
   std::vector<MnUserParameterState> states;
   //   double edmmax = 0.5*0.05*fFCN.Up()*1.e-3;

   //double toler = 0.05;
   double toler = 0.1; // use same defaut value as in Minos

   //get first four points
   //   std::cout<<"MnContours: get first 4 params."<<std::endl;
   MnMinos minos(fFCN, fMinimum, fStrategy);

   double valx = fMinimum.UserState().Value(px);
   double valy = fMinimum.UserState().Value(py);

   MinosError mex = minos.Minos(px);
   nfcn += mex.NFcn();
   if(!mex.IsValid()) {
      MN_ERROR_MSG("MnContours is unable to find first two points.");
      return ContoursError(px, py, result, mex, mex, nfcn);
   }
   std::pair<double,double> ex = mex();

   MinosError mey = minos.Minos(py);
   nfcn += mey.NFcn();
   if(!mey.IsValid()) {
      MN_ERROR_MSG("MnContours is unable to find second two points.");
      return ContoursError(px, py, result, mex, mey, nfcn);
   }
   std::pair<double,double> ey = mey();

   MnMigrad migrad(fFCN, fMinimum.UserState(), MnStrategy(std::max(0, int(fStrategy.Strategy()-1))));

   migrad.Fix(px);
   migrad.SetValue(px, valx + ex.second);
   FunctionMinimum exy_up = migrad();
   nfcn += exy_up.NFcn();
   if(!exy_up.IsValid()) {
      MN_ERROR_VAL2("MnContours: unable to find Upper y Value for x Parameter",px);
      return ContoursError(px, py, result, mex, mey, nfcn);
   }

   migrad.SetValue(px, valx + ex.first);
   FunctionMinimum exy_lo = migrad();
   nfcn += exy_lo.NFcn();
   if(!exy_lo.IsValid()) {
      MN_ERROR_VAL2("MnContours: unable to find Lower y Value for x Parameter",px);
      return ContoursError(px, py, result, mex, mey, nfcn);
   }

   MnMigrad migrad1(fFCN, fMinimum.UserState(), MnStrategy(std::max(0, int(fStrategy.Strategy()-1))));
   migrad1.Fix(py);
   migrad1.SetValue(py, valy + ey.second);
   FunctionMinimum eyx_up = migrad1();
   nfcn += eyx_up.NFcn();
   if(!eyx_up.IsValid()) {
      MN_ERROR_VAL2("MnContours: unable to find Upper x Value for y Parameter",py);
      return ContoursError(px, py, result, mex, mey, nfcn);
   }

   migrad1.SetValue(py, valy + ey.first);
   FunctionMinimum eyx_lo = migrad1();
   nfcn += eyx_lo.NFcn();
   if(!eyx_lo.IsValid()) {
      MN_ERROR_VAL2("MnContours: unable to find Lower x Value for y Parameter",py);
      return ContoursError(px, py, result, mex, mey, nfcn);
   }

   double scalx = 1./(ex.second - ex.first);
   double scaly = 1./(ey.second - ey.first);

   result.push_back(std::pair<double,double>(valx + ex.first, exy_lo.UserState().Value(py)));
   result.push_back(std::pair<double,double>(eyx_lo.UserState().Value(px), valy + ey.first));
   result.push_back(std::pair<double,double>(valx + ex.second, exy_up.UserState().Value(py)));
   result.push_back(std::pair<double,double>(eyx_up.UserState().Value(px), valy + ey.second));

   MnUserParameterState upar = fMinimum.UserState();

   //   std::cout<<"MnContours: first 4 params finished."<<std::endl;
   int printLevel = MnPrint::Level();

   if (printLevel > 0 ) {
      std::cout << "MnContour : List of found points " << std::endl;
      std::cout << "\t Parameter x is " << upar.Name(px) << std::endl;
      std::cout << "\t Parameter y is " << upar.Name(py) << std::endl;
   }

   if (printLevel > 0) {
      for (unsigned int i = 0; i < 4; ++i)
         PrintContourPoint(result[i] );
   }

   upar.Fix(px);
   upar.Fix(py);

   std::vector<unsigned int> par(2); par[0] = px; par[1] = py;
   MnFunctionCross cross(fFCN, upar, fMinimum.Fval(), fStrategy);

   for(unsigned int i = 4; i < npoints; i++) {

      std::vector<std::pair<double,double> >::iterator idist1 = result.end()-1;
      std::vector<std::pair<double,double> >::iterator idist2 = result.begin();
      double dx = idist1->first - (idist2)->first;
      double dy = idist1->second - (idist2)->second;
      double bigdis = scalx*scalx*dx*dx + scaly*scaly*dy*dy;

      for(std::vector<std::pair<double,double> >::iterator ipair = result.begin(); ipair != result.end()-1; ipair++) {
         double distx = ipair->first - (ipair+1)->first;
         double disty = ipair->second - (ipair+1)->second;
         double dist = scalx*scalx*distx*distx + scaly*scaly*disty*disty;
         if(dist > bigdis) {
            bigdis = dist;
            idist1 = ipair;
            idist2 = ipair+1;
         }
      }

      double a1 = 0.5;
      double a2 = 0.5;
      double sca = 1.;

L300:

      if(nfcn > maxcalls) {
         MN_ERROR_MSG("MnContours: maximum number of function calls exhausted.");
         return ContoursError(px, py, result, mex, mey, nfcn);
      }

      double xmidcr = a1*idist1->first + a2*(idist2)->first;
      double ymidcr = a1*idist1->second + a2*(idist2)->second;
      double xdir = (idist2)->second - idist1->second;
      double ydir = idist1->first - (idist2)->first;
      double scalfac = sca*std::max(fabs(xdir*scalx), fabs(ydir*scaly));
      double xdircr = xdir/scalfac;
      double ydircr = ydir/scalfac;
      std::vector<double> pmid(2); pmid[0] = xmidcr; pmid[1] = ymidcr;
      std::vector<double> pdir(2); pdir[0] = xdircr; pdir[1] = ydircr;

      MnCross opt = cross(par, pmid, pdir, toler, maxcalls);
      nfcn += opt.NFcn();
      if(!opt.IsValid()) {
         //       if(a1 > 0.5) {
         if(sca < 0.) {
            MN_ERROR_VAL2("MnContours : unable to find point on Contour",i+1);
            MN_ERROR_VAL2("MnContours : found  only i points",i);
            return ContoursError(px, py, result, mex, mey, nfcn);
         }
         //       a1 = 0.75;
         //       a2 = 0.25;
         //       std::cout<<"*****switch direction"<<std::endl;
         sca = -1.;
         goto L300;
         }
      double aopt = opt.Value();
      if(idist2 == result.begin()) {
         result.push_back(std::pair<double,double>(xmidcr+(aopt)*xdircr, ymidcr + (aopt)*ydircr));
         if (printLevel > 0) PrintContourPoint( result.back() );
      }
      else {
         result.insert(idist2, std::pair<double,double>(xmidcr+(aopt)*xdircr, ymidcr + (aopt)*ydircr));
         if (printLevel > 0) PrintContourPoint( *idist2 );
      }
   }
   if (printLevel >0)
      std::cout << "MnContour: Number of contour points = " << result.size() << std::endl;

   return ContoursError(px, py, result, mex, mey, nfcn);
}

   }  // namespace Minuit2

}  // namespace ROOT
<|endoftext|>