<commit_before>/**
 * \file
 * \brief RawFifoQueue class header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * 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/.
 *
 * \date 2015-01-01
 */

#ifndef INCLUDE_DISTORTOS_RAWFIFOQUEUE_HPP_
#define INCLUDE_DISTORTOS_RAWFIFOQUEUE_HPP_

#include "distortos/scheduler/FifoQueueBase.hpp"

namespace distortos
{

/// RawFifoQueue class is very similar to FifoQueue, but optimized for binary serializable types (like POD types). Type
/// T can be used with both RawFifoQueue and FifoQueue<T> only when std::is_trivially_copyable<T>::value == true,
/// otherwise only FifoQueue<T> use is safe, while using RawFifoQueue results in undefined behavior.
class RawFifoQueue
{
public:

	/**
	 * \brief RawFifoQueue's constructor
	 *
	 * \param [in] storage is a memory block for elements, sufficiently large for \a maxElements, each \a elementSize
	 * bytes long
	 * \param [in] elementSize is the size of single queue element, bytes
	 * \param [in] maxElements is the number of elements in storage memory block
	 */

	RawFifoQueue(void* storage, size_t elementSize, size_t maxElements);

	/**
	 * \brief Pops the oldest (first) element from the queue.
	 *
	 * \param [out] buffer is a pointer to buffer for popped element
	 * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	int pop(void* buffer, size_t size);

	/**
	 * \brief Pops the oldest (first) element from the queue.
	 *
	 * \param T is the type of data popped from the queue
	 *
	 * \param [out] buffer is a reference to object that will be used to return popped value
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename T>
	int pop(T& buffer)
	{
		return pop(&buffer, sizeof(buffer));
	}

	/**
	 * \brief Pushes the element to the queue.
	 *
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	int push(const void* data, size_t size);

	/**
	 * \brief Pushes the element to the queue.
	 *
	 * \param T is the type of data pushed to the queue
	 *
	 * \param [in] data is a reference to data that will be pushed to RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename T>
	int push(const T& data)
	{
		return push(&data, sizeof(data));
	}

	/**
	 * \brief Tries to pop the oldest (first) element from the queue.
	 *
	 * \param [out] buffer is a pointer to buffer for popped element
	 * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPop(void* buffer, size_t size);

	/**
	 * \brief Tries to pop the oldest (first) element from the queue.
	 *
	 * \param T is the type of data popped from the queue
	 *
	 * \param [out] buffer is a reference to object that will be used to return popped value
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename T>
	int tryPop(T& buffer)
	{
		return tryPop(&buffer, sizeof(buffer));
	}

	/**
	 * \brief Tries to pop the oldest (first) element from the queue for a given duration of time.
	 *
	 * \param [in] duration is the duration after which the call will be terminated without popping the element
	 * \param [out] buffer is a pointer to buffer for popped element
	 * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPopFor(TickClock::duration duration, void* buffer, size_t size);

	/**
	 * \brief Tries to pop the oldest (first) element from the queue for a given duration of time.
	 *
	 * Template variant of tryPopFor(TickClock::duration, void*, size_t).
	 *
	 * \param Rep is type of tick counter
	 * \param Period is std::ratio type representing the tick period of the clock, in seconds
	 *
	 * \param [in] duration is the duration after which the call will be terminated without popping the element
	 * \param [out] buffer is a pointer to buffer for popped element
	 * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename Rep, typename Period>
	int tryPopFor(const std::chrono::duration<Rep, Period> duration, void* const buffer, const size_t size)
	{
		return tryPopFor(std::chrono::duration_cast<TickClock::duration>(duration), buffer, size);
	}

	/**
	 * \brief Tries to pop the oldest (first) element from the queue for a given duration of time.
	 *
	 * \param Rep is type of tick counter
	 * \param Period is std::ratio type representing the tick period of the clock, in seconds
	 * \param T is the type of data popped from the queue
	 *
	 * \param [in] duration is the duration after which the call will be terminated without popping the element
	 * \param [out] buffer is a reference to object that will be used to return popped value
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename Rep, typename Period, typename T>
	int tryPopFor(const std::chrono::duration<Rep, Period> duration, T& buffer)
	{
		return tryPopFor(std::chrono::duration_cast<TickClock::duration>(duration), &buffer, sizeof(buffer));
	}

	/**
	 * \brief Tries to push the element to the queue.
	 *
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPush(const void* data, size_t size);

	/**
	 * \brief Tries to push the element to the queue.
	 *
	 * \param T is the type of data pushed to the queue
	 *
	 * \param [in] data is a reference to data that will be pushed to RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename T>
	int tryPush(const T& data)
	{
		return tryPush(&data, sizeof(data));
	}

	/**
	 * \brief Tries to push the element to the queue for a given duration of time.
	 *
	 * \param [in] duration is the duration after which the wait will be terminated without pushing the element
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPushFor(TickClock::duration duration, const void* data, size_t size);

	/**
	 * \brief Tries to push the element to the queue for a given duration of time.
	 *
	 * Template variant of tryPushFor(TickClock::duration, const void*, size_t).
	 *
	 * \param Rep is type of tick counter
	 * \param Period is std::ratio type representing the tick period of the clock, in seconds
	 *
	 * \param [in] duration is the duration after which the wait will be terminated without pushing the element
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename Rep, typename Period>
	int tryPushFor(const std::chrono::duration<Rep, Period> duration, const void* const data, const size_t size)
	{
		return tryPushFor(std::chrono::duration_cast<TickClock::duration>(duration), data, size);
	}

	/**
	 * \brief Tries to push the element to the queue for a given duration of time.
	 *
	 * \param Rep is type of tick counter
	 * \param Period is std::ratio type representing the tick period of the clock, in seconds
	 * \param T is the type of data pushed to the queue
	 *
	 * \param [in] duration is the duration after which the wait will be terminated without pushing the element
	 * \param [in] data is a reference to data that will be pushed to RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename Rep, typename Period, typename T>
	int tryPushFor(const std::chrono::duration<Rep, Period> duration, const T& data)
	{
		return tryPushFor(std::chrono::duration_cast<TickClock::duration>(duration), &data, sizeof(data));
	}

	/**
	 * \brief Tries to push the element to the queue until a given time point.
	 *
	 * \param [in] timePoint is the time point at which the call will be terminated without pushing the element
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitUntil();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPushUntil(TickClock::time_point timePoint, const void* data, size_t size);

private:

	/**
	 * \brief Pops the oldest (first) element from the queue.
	 *
	 * Internal version - builds the Functor object.
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a popSemaphore_
	 * \param [out] buffer is a pointer to buffer for popped element
	 * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int popInternal(const scheduler::SemaphoreFunctor& waitSemaphoreFunctor, void* buffer, size_t size);

	/**
	 * \brief Pushes the element to the queue.
	 *
	 * Internal version - builds the Functor object.
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a pushSemaphore_
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int pushInternal(const scheduler::SemaphoreFunctor& waitSemaphoreFunctor, const void* data, size_t size);

	/// contained scheduler::FifoQueueBase object which implements base functionality
	scheduler::FifoQueueBase fifoQueueBase_;

	/// size of single queue element, bytes
	const size_t elementSize_;
};

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_RAWFIFOQUEUE_HPP_
<commit_msg>RawFifoQueue: add RawFifoQueue::tryPushUntil() variant with template time point<commit_after>/**
 * \file
 * \brief RawFifoQueue class header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * 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/.
 *
 * \date 2015-01-01
 */

#ifndef INCLUDE_DISTORTOS_RAWFIFOQUEUE_HPP_
#define INCLUDE_DISTORTOS_RAWFIFOQUEUE_HPP_

#include "distortos/scheduler/FifoQueueBase.hpp"

namespace distortos
{

/// RawFifoQueue class is very similar to FifoQueue, but optimized for binary serializable types (like POD types). Type
/// T can be used with both RawFifoQueue and FifoQueue<T> only when std::is_trivially_copyable<T>::value == true,
/// otherwise only FifoQueue<T> use is safe, while using RawFifoQueue results in undefined behavior.
class RawFifoQueue
{
public:

	/**
	 * \brief RawFifoQueue's constructor
	 *
	 * \param [in] storage is a memory block for elements, sufficiently large for \a maxElements, each \a elementSize
	 * bytes long
	 * \param [in] elementSize is the size of single queue element, bytes
	 * \param [in] maxElements is the number of elements in storage memory block
	 */

	RawFifoQueue(void* storage, size_t elementSize, size_t maxElements);

	/**
	 * \brief Pops the oldest (first) element from the queue.
	 *
	 * \param [out] buffer is a pointer to buffer for popped element
	 * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	int pop(void* buffer, size_t size);

	/**
	 * \brief Pops the oldest (first) element from the queue.
	 *
	 * \param T is the type of data popped from the queue
	 *
	 * \param [out] buffer is a reference to object that will be used to return popped value
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename T>
	int pop(T& buffer)
	{
		return pop(&buffer, sizeof(buffer));
	}

	/**
	 * \brief Pushes the element to the queue.
	 *
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	int push(const void* data, size_t size);

	/**
	 * \brief Pushes the element to the queue.
	 *
	 * \param T is the type of data pushed to the queue
	 *
	 * \param [in] data is a reference to data that will be pushed to RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::wait();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename T>
	int push(const T& data)
	{
		return push(&data, sizeof(data));
	}

	/**
	 * \brief Tries to pop the oldest (first) element from the queue.
	 *
	 * \param [out] buffer is a pointer to buffer for popped element
	 * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPop(void* buffer, size_t size);

	/**
	 * \brief Tries to pop the oldest (first) element from the queue.
	 *
	 * \param T is the type of data popped from the queue
	 *
	 * \param [out] buffer is a reference to object that will be used to return popped value
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename T>
	int tryPop(T& buffer)
	{
		return tryPop(&buffer, sizeof(buffer));
	}

	/**
	 * \brief Tries to pop the oldest (first) element from the queue for a given duration of time.
	 *
	 * \param [in] duration is the duration after which the call will be terminated without popping the element
	 * \param [out] buffer is a pointer to buffer for popped element
	 * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPopFor(TickClock::duration duration, void* buffer, size_t size);

	/**
	 * \brief Tries to pop the oldest (first) element from the queue for a given duration of time.
	 *
	 * Template variant of tryPopFor(TickClock::duration, void*, size_t).
	 *
	 * \param Rep is type of tick counter
	 * \param Period is std::ratio type representing the tick period of the clock, in seconds
	 *
	 * \param [in] duration is the duration after which the call will be terminated without popping the element
	 * \param [out] buffer is a pointer to buffer for popped element
	 * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename Rep, typename Period>
	int tryPopFor(const std::chrono::duration<Rep, Period> duration, void* const buffer, const size_t size)
	{
		return tryPopFor(std::chrono::duration_cast<TickClock::duration>(duration), buffer, size);
	}

	/**
	 * \brief Tries to pop the oldest (first) element from the queue for a given duration of time.
	 *
	 * \param Rep is type of tick counter
	 * \param Period is std::ratio type representing the tick period of the clock, in seconds
	 * \param T is the type of data popped from the queue
	 *
	 * \param [in] duration is the duration after which the call will be terminated without popping the element
	 * \param [out] buffer is a reference to object that will be used to return popped value
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename Rep, typename Period, typename T>
	int tryPopFor(const std::chrono::duration<Rep, Period> duration, T& buffer)
	{
		return tryPopFor(std::chrono::duration_cast<TickClock::duration>(duration), &buffer, sizeof(buffer));
	}

	/**
	 * \brief Tries to push the element to the queue.
	 *
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPush(const void* data, size_t size);

	/**
	 * \brief Tries to push the element to the queue.
	 *
	 * \param T is the type of data pushed to the queue
	 *
	 * \param [in] data is a reference to data that will be pushed to RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWait();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename T>
	int tryPush(const T& data)
	{
		return tryPush(&data, sizeof(data));
	}

	/**
	 * \brief Tries to push the element to the queue for a given duration of time.
	 *
	 * \param [in] duration is the duration after which the wait will be terminated without pushing the element
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPushFor(TickClock::duration duration, const void* data, size_t size);

	/**
	 * \brief Tries to push the element to the queue for a given duration of time.
	 *
	 * Template variant of tryPushFor(TickClock::duration, const void*, size_t).
	 *
	 * \param Rep is type of tick counter
	 * \param Period is std::ratio type representing the tick period of the clock, in seconds
	 *
	 * \param [in] duration is the duration after which the wait will be terminated without pushing the element
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename Rep, typename Period>
	int tryPushFor(const std::chrono::duration<Rep, Period> duration, const void* const data, const size_t size)
	{
		return tryPushFor(std::chrono::duration_cast<TickClock::duration>(duration), data, size);
	}

	/**
	 * \brief Tries to push the element to the queue for a given duration of time.
	 *
	 * \param Rep is type of tick counter
	 * \param Period is std::ratio type representing the tick period of the clock, in seconds
	 * \param T is the type of data pushed to the queue
	 *
	 * \param [in] duration is the duration after which the wait will be terminated without pushing the element
	 * \param [in] data is a reference to data that will be pushed to RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - sizeof(T) doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitFor();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename Rep, typename Period, typename T>
	int tryPushFor(const std::chrono::duration<Rep, Period> duration, const T& data)
	{
		return tryPushFor(std::chrono::duration_cast<TickClock::duration>(duration), &data, sizeof(data));
	}

	/**
	 * \brief Tries to push the element to the queue until a given time point.
	 *
	 * \param [in] timePoint is the time point at which the call will be terminated without pushing the element
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitUntil();
	 * - error codes returned by Semaphore::post();
	 */

	int tryPushUntil(TickClock::time_point timePoint, const void* data, size_t size);

	/**
	 * \brief Tries to push the element to the queue until a given time point.
	 *
	 * Template variant of tryPushUntil(TickClock::time_point, const void*, size_t).
	 *
	 * \param Duration is a std::chrono::duration type used to measure duration
	 *
	 * \param [in] timePoint is the time point at which the call will be terminated without pushing the element
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by Semaphore::tryWaitUntil();
	 * - error codes returned by Semaphore::post();
	 */

	template<typename Duration>
	int tryPushUntil(const std::chrono::time_point<TickClock, Duration> timePoint, const void* const data,
			const size_t size)
	{
		return tryPushUntil(std::chrono::time_point_cast<TickClock::duration>(timePoint), data, size);
	}

private:

	/**
	 * \brief Pops the oldest (first) element from the queue.
	 *
	 * Internal version - builds the Functor object.
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a popSemaphore_
	 * \param [out] buffer is a pointer to buffer for popped element
	 * \param [in] size is the size of \a buffer, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was popped successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int popInternal(const scheduler::SemaphoreFunctor& waitSemaphoreFunctor, void* buffer, size_t size);

	/**
	 * \brief Pushes the element to the queue.
	 *
	 * Internal version - builds the Functor object.
	 *
	 * \param [in] waitSemaphoreFunctor is a reference to SemaphoreFunctor which will be executed with \a pushSemaphore_
	 * \param [in] data is a pointer to data that will be pushed to RawFifoQueue
	 * \param [in] size is the size of \a data, bytes - must be equal to the \a elementSize attribute of RawFifoQueue
	 *
	 * \return zero if element was pushed successfully, error code otherwise:
	 * - EMSGSIZE - \a size doesn't match the \a elementSize attribute of RawFifoQueue;
	 * - error codes returned by \a waitSemaphoreFunctor's operator() call;
	 * - error codes returned by Semaphore::post();
	 */

	int pushInternal(const scheduler::SemaphoreFunctor& waitSemaphoreFunctor, const void* data, size_t size);

	/// contained scheduler::FifoQueueBase object which implements base functionality
	scheduler::FifoQueueBase fifoQueueBase_;

	/// size of single queue element, bytes
	const size_t elementSize_;
};

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_RAWFIFOQUEUE_HPP_
<|endoftext|>


<commit_before>//
// Copyright (c) 2005, 2006, 2007, 2008, 2009, 2010, 2011 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_PROBLEM_SOLVER_HH
# define HPP_CORE_PROBLEM_SOLVER_HH

# include <hpp/model/fwd.hh>
# include <hpp/core/deprecated.hh>
# include <hpp/core/problem.hh>
# include <hpp/core/fwd.hh>
# include <hpp/core/config.hh>

namespace hpp {
  namespace core {
    /// Set and solve a path planning problem

    class HPP_CORE_DLLAPI ProblemSolver {
    public:
      /// Constructor
      ProblemSolver ();

      /// Destructor
      virtual ~ProblemSolver ();

      /// Set robot
      void robot (const DevicePtr_t& robot);

      /// Get robot
      const DevicePtr_t& robot () const;

      /// Get pointer to problem
      ProblemPtr_t problem ()
      {
	return problem_;
      }
      /// Get shared pointer to initial configuration.
      const ConfigurationPtr_t& initConfig () const
      {
	return initConf_;
      }
      /// Set initial configuration.
      void initConfig (const ConfigurationPtr_t& config);
      /// Get number of goal configuration.
      const Configurations_t& goalConfigs () const;
      /// Add goal configuration.
      void addGoalConfig (const ConfigurationPtr_t& config);
      /// Reset the set of goal configurations
      void resetGoalConfigs ();
      /// Set path planner type
      void pathPlannerType (const std::string& type);
      /// Get path planner
      const PathPlannerPtr_t& pathPlanner () const
      {
	return pathPlanner_;
      }

      /// Set path optimizer type
      void pathOptimizerType (const std::string& type);
      /// Get path optimizer
      const PathOptimizerPtr_t& pathOptimizer () const
      {
	return pathOptimizer_;
      }

      const RoadmapPtr_t& roadmap () const
      {
	return roadmap_;
      }

      /// Add a constraint
      void addConstraint (const ConstraintPtr_t& constraint);

      /// Get constraint set
      const ConstraintSetPtr_t& constraints () const
      {
	return constraints_;
      }

      /// Reset constraint set
      void resetConstraints ();

      /// Create new problem.
      void resetProblem ();

      /// \name Solve problem and get paths
      /// \{

      /// Set and solve the problem
      void solve ();

      /// Add a path
      void addPath (const PathVectorPtr_t& path)
      {
	paths_.push_back (path);
      }

      /// Return vector of paths
      const PathVectors_t& paths () const
      {
	return paths_;
      }
      /// \}

      /// \name Obstacles
      /// \{

      /// Add obstacle to the list.
      /// \param inObject a new object.
      /// \param collision whether collision checking should be performed
      ///        for this object.
      /// \param distance whether distance computation should be performed
      ///        for this object.
      void addObstacle (const CollisionObjectPtr_t& inObject, bool collision,
			bool distance);
      /// \}

    private:
      typedef boost::function < PathPlannerPtr_t (const Problem&,
						  const RoadmapPtr_t&) >
	PathPlannerBuilder_t;
      typedef boost::function < PathOptimizerPtr_t (const Problem&) >
	PathOptimizerBuilder_t;
      typedef std::map < std::string, PathPlannerBuilder_t >
	PathPlannerFactory_t;
      ///Map (string , constructor of path optimizer)
      typedef std::map < std::string, PathOptimizerBuilder_t >
	PathOptimizerFactory_t;
      /// Robot
      DevicePtr_t robot_;
      bool robotChanged_;
      /// Problem
      ProblemPtr_t problem_;
      /// Shared pointer to initial configuration.
      ConfigurationPtr_t initConf_;
      /// Shared pointer to goal configuration.
      Configurations_t goalConfigurations_;
      /// Path planner
      std::string pathPlannerType_;
      PathPlannerPtr_t pathPlanner_;
      /// Path optimizer
      std::string pathOptimizerType_;
      PathOptimizerPtr_t pathOptimizer_;
      /// Store roadmap
      RoadmapPtr_t roadmap_;
      /// Paths
      PathVectors_t paths_;
      /// Path planner factory
      PathPlannerFactory_t pathPlannerFactory_;
      /// Path optimizer factory
      PathOptimizerFactory_t pathOptimizerFactory_;
      /// Store constraints until call to solve.
      ConstraintSetPtr_t constraints_;
      /// Store obstacles until call to solve.
      ObjectVector_t collisionObstacles_;
      ObjectVector_t distanceObstacles_;
    }; // class ProblemSolver
  } // namespace core
} // namespace hpp

#endif // HPP_CORE_PROBLEM_SOLVER_HH
<commit_msg>Make ProblemSolver::robot setter virtual.<commit_after>//
// Copyright (c) 2005, 2006, 2007, 2008, 2009, 2010, 2011 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_PROBLEM_SOLVER_HH
# define HPP_CORE_PROBLEM_SOLVER_HH

# include <hpp/model/fwd.hh>
# include <hpp/core/deprecated.hh>
# include <hpp/core/problem.hh>
# include <hpp/core/fwd.hh>
# include <hpp/core/config.hh>

namespace hpp {
  namespace core {
    /// Set and solve a path planning problem

    class HPP_CORE_DLLAPI ProblemSolver {
    public:
      /// Constructor
      ProblemSolver ();

      /// Destructor
      virtual ~ProblemSolver ();

      /// Set robot
      virtual void robot (const DevicePtr_t& robot);

      /// Get robot
      const DevicePtr_t& robot () const;

      /// Get pointer to problem
      ProblemPtr_t problem ()
      {
	return problem_;
      }
      /// Get shared pointer to initial configuration.
      const ConfigurationPtr_t& initConfig () const
      {
	return initConf_;
      }
      /// Set initial configuration.
      void initConfig (const ConfigurationPtr_t& config);
      /// Get number of goal configuration.
      const Configurations_t& goalConfigs () const;
      /// Add goal configuration.
      void addGoalConfig (const ConfigurationPtr_t& config);
      /// Reset the set of goal configurations
      void resetGoalConfigs ();
      /// Set path planner type
      void pathPlannerType (const std::string& type);
      /// Get path planner
      const PathPlannerPtr_t& pathPlanner () const
      {
	return pathPlanner_;
      }

      /// Set path optimizer type
      void pathOptimizerType (const std::string& type);
      /// Get path optimizer
      const PathOptimizerPtr_t& pathOptimizer () const
      {
	return pathOptimizer_;
      }

      const RoadmapPtr_t& roadmap () const
      {
	return roadmap_;
      }

      /// Add a constraint
      void addConstraint (const ConstraintPtr_t& constraint);

      /// Get constraint set
      const ConstraintSetPtr_t& constraints () const
      {
	return constraints_;
      }

      /// Reset constraint set
      void resetConstraints ();

      /// Create new problem.
      void resetProblem ();

      /// \name Solve problem and get paths
      /// \{

      /// Set and solve the problem
      void solve ();

      /// Add a path
      void addPath (const PathVectorPtr_t& path)
      {
	paths_.push_back (path);
      }

      /// Return vector of paths
      const PathVectors_t& paths () const
      {
	return paths_;
      }
      /// \}

      /// \name Obstacles
      /// \{

      /// Add obstacle to the list.
      /// \param inObject a new object.
      /// \param collision whether collision checking should be performed
      ///        for this object.
      /// \param distance whether distance computation should be performed
      ///        for this object.
      void addObstacle (const CollisionObjectPtr_t& inObject, bool collision,
			bool distance);
      /// \}

    private:
      typedef boost::function < PathPlannerPtr_t (const Problem&,
						  const RoadmapPtr_t&) >
	PathPlannerBuilder_t;
      typedef boost::function < PathOptimizerPtr_t (const Problem&) >
	PathOptimizerBuilder_t;
      typedef std::map < std::string, PathPlannerBuilder_t >
	PathPlannerFactory_t;
      ///Map (string , constructor of path optimizer)
      typedef std::map < std::string, PathOptimizerBuilder_t >
	PathOptimizerFactory_t;
      /// Robot
      DevicePtr_t robot_;
      bool robotChanged_;
      /// Problem
      ProblemPtr_t problem_;
      /// Shared pointer to initial configuration.
      ConfigurationPtr_t initConf_;
      /// Shared pointer to goal configuration.
      Configurations_t goalConfigurations_;
      /// Path planner
      std::string pathPlannerType_;
      PathPlannerPtr_t pathPlanner_;
      /// Path optimizer
      std::string pathOptimizerType_;
      PathOptimizerPtr_t pathOptimizer_;
      /// Store roadmap
      RoadmapPtr_t roadmap_;
      /// Paths
      PathVectors_t paths_;
      /// Path planner factory
      PathPlannerFactory_t pathPlannerFactory_;
      /// Path optimizer factory
      PathOptimizerFactory_t pathOptimizerFactory_;
      /// Store constraints until call to solve.
      ConstraintSetPtr_t constraints_;
      /// Store obstacles until call to solve.
      ObjectVector_t collisionObstacles_;
      ObjectVector_t distanceObstacles_;
    }; // class ProblemSolver
  } // namespace core
} // namespace hpp

#endif // HPP_CORE_PROBLEM_SOLVER_HH
<|endoftext|>


<commit_before>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_SHARED_UTILS_HPP
#define RJ_SHARED_UTILS_HPP

#include <SFML/Graphics.hpp>

#include <mlk/graphics/color.h>

#include <cmath>

namespace rj
{
	template<typename T>
	T round_to(T value, T to)
	{return (std::round(value / to)) * to;}

	template<typename T>
	sf::Vector2<T> operator-(const sf::Vector2<T>& vec, T minus)
	{return {vec.x - minus, vec.y - minus};}

	template<typename T>
	sf::Vector2<T> operator+(const sf::Vector2<T>& vec, T plus)
	{return {vec.x + plus, vec.y + plus};}

	template<typename T>
	sf::Rect<T> bounds_from_vec(const sf::Vector2<T>& v, const sf::Vector2<T>& size = {1, 1})
	{return {{v.x, v.y}, size};}

	inline sf::Color to_rgb(const std::string& hex_str, std::uint8_t custom_alpha = 255)
	{
		mlk::gcs::color_rgb tmp{hex_str};
		return {tmp.red(), tmp.green(), tmp.blue(), custom_alpha};
	}

	inline sf::Color operator""_rgb(const char* str, std::size_t size)
	{return to_rgb({str, size});}
}

#endif // RJ_SHARED_UTILS_HPP
<commit_msg>added flip_h<T>(...)<commit_after>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_SHARED_UTILS_HPP
#define RJ_SHARED_UTILS_HPP

#include <SFML/Graphics.hpp>

#include <mlk/graphics/color.h>

#include <cmath>

namespace rj
{
	template<typename T>
	T round_to(T value, T to)
	{return (std::round(value / to)) * to;}

	template<typename T>
	sf::Vector2<T> operator-(const sf::Vector2<T>& vec, T minus)
	{return {vec.x - minus, vec.y - minus};}

	template<typename T>
	sf::Vector2<T> operator+(const sf::Vector2<T>& vec, T plus)
	{return {vec.x + plus, vec.y + plus};}

	template<typename T>
	sf::Rect<T> bounds_from_vec(const sf::Vector2<T>& v, const sf::Vector2<T>& size = {1, 1})
	{return {{v.x, v.y}, size};}

	template<typename T>
	void flip_h(T& obj)
	{obj.rotate(180.f);}

	inline sf::Color to_rgb(const std::string& hex_str, std::uint8_t custom_alpha = 255)
	{
		mlk::gcs::color_rgb tmp{hex_str};
		return {tmp.red(), tmp.green(), tmp.blue(), custom_alpha};
	}

	inline sf::Color operator""_rgb(const char* str, std::size_t size)
	{return to_rgb({str, size});}
}

#endif // RJ_SHARED_UTILS_HPP
<|endoftext|>


<commit_before>#include "sn_sweeper.hpp"

#include <algorithm>
#include <string>

#include "pugixml.hpp"

#include "files.hpp"
#include "string_utils.hpp"

namespace {
    using namespace mocc;
    BC_Size_t boundary_helper( const Mesh &mesh ) {
        BC_Size_t bc_size = { (int)mesh.ny()*(int)mesh.nz(),
                              (int)mesh.nx()*(int)mesh.nz(),
                              (int)mesh.nx()*(int)mesh.ny() };
        return bc_size;
    }
}

namespace mocc {
namespace sn {
    SnSweeper::SnSweeper( const pugi::xml_node &input, const CoreMesh& mesh ):
            TransportSweeper( input ),
            timer_( RootTimer.new_timer("Sn Sweeper", true) ),
            timer_init_( timer_.new_timer("Initialization", true) ),
            timer_sweep_( timer_.new_timer("Sweep", false) ),
            mesh_( mesh ),
            bc_type_( mesh.boundary() ),
            flux_1g_( ),
            xstr_( mesh.n_pin() ),
            bc_in_( mesh.mat_lib().n_group(), ang_quad_, bc_type_,
                    boundary_helper(mesh) ),
            bc_out_( 1, ang_quad_, bc_type_, boundary_helper(mesh) ),
            gs_boundary_( true )
    {
        LogFile << "Constructing a base Sn sweeper" << std::endl;

        // Set up the cross-section mesh. If there is <data> specified, try to
        // use that, otherwise generate volume-weighted cross sections
        if( input.child("data").empty() ) {
            xs_mesh_ = SP_XSMesh_t( new XSMeshHomogenized(mesh) );
        } else {
            try {
                xs_mesh_ = SP_XSMesh_t( new XSMeshHomogenized(mesh, input) );
            }
            catch( Exception e ) {
                std::cerr << e.what() << std::endl;
                throw EXCEPT("Failed to create XSMesh for Sn Sweeper.");
            }
        }

        core_mesh_ = &mesh;
        n_reg_ = mesh.n_pin();
        n_group_ = xs_mesh_->n_group();
        flux_.resize( n_reg_, n_group_ );
        flux_old_.resize( n_reg_, n_group_ );
        vol_.resize( n_reg_ );

        // Set the mesh volumes. Same as the pin volumes
        int ipin = 0;
        for( auto &pin: mesh_ ) {
            int i = mesh_.coarse_cell( mesh_.pin_position(ipin) );
            vol_[i] = pin->vol();
            ipin++;
        }

        // Make sure we have input from the XML
        if( input.empty() ) {
            throw EXCEPT("No input specified to initialize Sn sweeper.");
        }

        // Parse the number of inner iterations
        int int_in = input.attribute("n_inner").as_int(-1);
        if( int_in < 0 ) {
            throw EXCEPT("Invalid number of inner iterations specified "
                    "(n_inner).");
        }
        n_inner_ = int_in;

        // Try to read boundary update option
        if( !input.attribute("boundary_update").empty() ) {
            std::string in_string =
                input.attribute("boundary_update").value();
            sanitize(in_string);

            if( (in_string == "gs") || (in_string == "gauss-seidel") ) {
                gs_boundary_ = true;
            } else if ( (in_string == "jacobi") || (in_string == "j") ) {
                gs_boundary_ = false;
            } else {
                throw EXCEPT("Unrecognized option for BC update!");
            }
        }
        // For now, the BC doesnt support parallel boundary updates, so
        // disable Gauss-Seidel boundary update if we are using multiple
        // threads.
        /// \todo Add support for multi-threaded G-S boundary update in Sn
        LogScreen << omp_get_max_threads() << " " << gs_boundary_ << std::endl;
        if( (omp_get_max_threads() > 1) && gs_boundary_ ) {
            gs_boundary_ = false;
            LogScreen << "WARNING: Disabling Gauss-Seidel boundary update "
                "in parallel Sn" << std::endl;
        }

        timer_.toc();
        timer_init_.toc();

        return;
    }

    /**
     * Watch out, this is potentially brittle, since it assumes parity between
     * the mesh regions and XS Mesh regions.
     */
    ArrayB3 SnSweeper::pin_powers() const {
        ArrayB3 powers(mesh_.nz(), mesh_.ny(), mesh_.nx());
        powers = 0.0;

        real_t tot_pow = 0.0;

        for(int ireg=0; ireg<n_reg_; ireg++ ) {
            auto pos = mesh_.coarse_position(ireg);
            const XSMeshRegion &xsr = (*xs_mesh_)[ireg];
            assert(xsr.reg().size() == 1);
            assert(xsr.reg()[0] == ireg);
            for( int ig=0; ig<n_group_; ig++ ) {
                real_t p = vol_[ireg] * flux_(ireg, ig) * xsr.xsmackf(ig);
                powers(pos.z, pos.y, pos.x) += p;
                tot_pow += p;
            }
        }

        tot_pow = powers.size()/tot_pow;

        powers *= tot_pow;

        return powers;
    }

    void SnSweeper::check_balance( int group ) const {
        if( !coarse_data_ ) {
            throw EXCEPT("No coarse data. Need it to look at currents.");
        }
        for( size_t icell=0; icell<mesh_.n_pin(); icell++ ) {
            real_t b = 0.0;

            // Current
            b -= coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::EAST), group ) *
                    mesh_.coarse_area( icell, Surface::EAST );
            b -= coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::NORTH), group ) *
                    mesh_.coarse_area( icell, Surface::NORTH );
            b -= coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::TOP), group ) *
                    mesh_.coarse_area( icell, Surface::TOP );
            b += coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::WEST), group ) *
                    mesh_.coarse_area( icell, Surface::WEST );
            b += coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::SOUTH), group ) *
                    mesh_.coarse_area( icell, Surface::SOUTH );
            b += coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::BOTTOM), group ) *
                    mesh_.coarse_area( icell, Surface::BOTTOM );

            // Source
            b += (*source_)[icell]*vol_[icell];

            // Internal removal
            b -= flux_1g_(icell) *
                (*xs_mesh_)[icell].xsmacrm()[group] * vol_[icell];

            std::cout << "Cell balance: " << b << std::endl;
        }
        std::cout << std::endl;
    }

    void SnSweeper::output( H5Node &node ) const {
        auto dims = mesh_.dimensions();
        std::reverse( dims.begin(), dims.end() );

        // Make a group in the file to store the flux
        node.create_group("flux");

        ArrayB2 flux = this->get_pin_flux();
        Normalize( flux.begin(), flux.end() );

        for( int ig=0; ig<n_group_; ig++ ) {
            std::stringstream setname;
            setname << "flux/" << std::setfill('0') << std::setw(3) << ig+1;

            ArrayB1 flux_1g = flux(blitz::Range::all(), ig);

            node.write( setname.str(), flux_1g.begin(), flux_1g.end(),
                    dims);
        }

        node.write( "pin_powers", this->pin_powers() );

        LogFile << "Sn Sweeper:" << std::endl;
        LogFile << "Angular Quadrature:" << std::endl;
        LogFile << ang_quad_ << std::endl;

        LogFile << "Boundary update: ";
        if( gs_boundary_ ) {
            LogFile << "Gauss-Seidel" << std::endl;
        } else {
            LogFile << "Jacobi" << std::endl;
        }

        LogFile << std::endl;

        xs_mesh_->output( node );
        return;
    }
} // namespace sn
} // namespace moc
<commit_msg>Add angular quadrature output to SnSweeper output<commit_after>#include "sn_sweeper.hpp"

#include <algorithm>
#include <string>

#include "pugixml.hpp"

#include "files.hpp"
#include "string_utils.hpp"

namespace {
    using namespace mocc;
    BC_Size_t boundary_helper( const Mesh &mesh ) {
        BC_Size_t bc_size = { (int)mesh.ny()*(int)mesh.nz(),
                              (int)mesh.nx()*(int)mesh.nz(),
                              (int)mesh.nx()*(int)mesh.ny() };
        return bc_size;
    }
}

namespace mocc {
namespace sn {
    SnSweeper::SnSweeper( const pugi::xml_node &input, const CoreMesh& mesh ):
            TransportSweeper( input ),
            timer_( RootTimer.new_timer("Sn Sweeper", true) ),
            timer_init_( timer_.new_timer("Initialization", true) ),
            timer_sweep_( timer_.new_timer("Sweep", false) ),
            mesh_( mesh ),
            bc_type_( mesh.boundary() ),
            flux_1g_( ),
            xstr_( mesh.n_pin() ),
            bc_in_( mesh.mat_lib().n_group(), ang_quad_, bc_type_,
                    boundary_helper(mesh) ),
            bc_out_( 1, ang_quad_, bc_type_, boundary_helper(mesh) ),
            gs_boundary_( true )
    {
        LogFile << "Constructing a base Sn sweeper" << std::endl;

        // Set up the cross-section mesh. If there is <data> specified, try to
        // use that, otherwise generate volume-weighted cross sections
        if( input.child("data").empty() ) {
            xs_mesh_ = SP_XSMesh_t( new XSMeshHomogenized(mesh) );
        } else {
            try {
                xs_mesh_ = SP_XSMesh_t( new XSMeshHomogenized(mesh, input) );
            }
            catch( Exception e ) {
                std::cerr << e.what() << std::endl;
                throw EXCEPT("Failed to create XSMesh for Sn Sweeper.");
            }
        }

        core_mesh_ = &mesh;
        n_reg_ = mesh.n_pin();
        n_group_ = xs_mesh_->n_group();
        flux_.resize( n_reg_, n_group_ );
        flux_old_.resize( n_reg_, n_group_ );
        vol_.resize( n_reg_ );

        // Set the mesh volumes. Same as the pin volumes
        int ipin = 0;
        for( auto &pin: mesh_ ) {
            int i = mesh_.coarse_cell( mesh_.pin_position(ipin) );
            vol_[i] = pin->vol();
            ipin++;
        }

        // Make sure we have input from the XML
        if( input.empty() ) {
            throw EXCEPT("No input specified to initialize Sn sweeper.");
        }

        // Parse the number of inner iterations
        int int_in = input.attribute("n_inner").as_int(-1);
        if( int_in < 0 ) {
            throw EXCEPT("Invalid number of inner iterations specified "
                    "(n_inner).");
        }
        n_inner_ = int_in;

        // Try to read boundary update option
        if( !input.attribute("boundary_update").empty() ) {
            std::string in_string =
                input.attribute("boundary_update").value();
            sanitize(in_string);

            if( (in_string == "gs") || (in_string == "gauss-seidel") ) {
                gs_boundary_ = true;
            } else if ( (in_string == "jacobi") || (in_string == "j") ) {
                gs_boundary_ = false;
            } else {
                throw EXCEPT("Unrecognized option for BC update!");
            }
        }
        // For now, the BC doesnt support parallel boundary updates, so
        // disable Gauss-Seidel boundary update if we are using multiple
        // threads.
        /// \todo Add support for multi-threaded G-S boundary update in Sn
        LogScreen << omp_get_max_threads() << " " << gs_boundary_ << std::endl;
        if( (omp_get_max_threads() > 1) && gs_boundary_ ) {
            gs_boundary_ = false;
            LogScreen << "WARNING: Disabling Gauss-Seidel boundary update "
                "in parallel Sn" << std::endl;
        }

        timer_.toc();
        timer_init_.toc();

        return;
    }

    /**
     * Watch out, this is potentially brittle, since it assumes parity between
     * the mesh regions and XS Mesh regions.
     */
    ArrayB3 SnSweeper::pin_powers() const {
        ArrayB3 powers(mesh_.nz(), mesh_.ny(), mesh_.nx());
        powers = 0.0;

        real_t tot_pow = 0.0;

        for(int ireg=0; ireg<n_reg_; ireg++ ) {
            auto pos = mesh_.coarse_position(ireg);
            const XSMeshRegion &xsr = (*xs_mesh_)[ireg];
            assert(xsr.reg().size() == 1);
            assert(xsr.reg()[0] == ireg);
            for( int ig=0; ig<n_group_; ig++ ) {
                real_t p = vol_[ireg] * flux_(ireg, ig) * xsr.xsmackf(ig);
                powers(pos.z, pos.y, pos.x) += p;
                tot_pow += p;
            }
        }

        tot_pow = powers.size()/tot_pow;

        powers *= tot_pow;

        return powers;
    }

    void SnSweeper::check_balance( int group ) const {
        if( !coarse_data_ ) {
            throw EXCEPT("No coarse data. Need it to look at currents.");
        }
        for( size_t icell=0; icell<mesh_.n_pin(); icell++ ) {
            real_t b = 0.0;

            // Current
            b -= coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::EAST), group ) *
                    mesh_.coarse_area( icell, Surface::EAST );
            b -= coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::NORTH), group ) *
                    mesh_.coarse_area( icell, Surface::NORTH );
            b -= coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::TOP), group ) *
                    mesh_.coarse_area( icell, Surface::TOP );
            b += coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::WEST), group ) *
                    mesh_.coarse_area( icell, Surface::WEST );
            b += coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::SOUTH), group ) *
                    mesh_.coarse_area( icell, Surface::SOUTH );
            b += coarse_data_->current(
                    mesh_.coarse_surf(icell, Surface::BOTTOM), group ) *
                    mesh_.coarse_area( icell, Surface::BOTTOM );

            // Source
            b += (*source_)[icell]*vol_[icell];

            // Internal removal
            b -= flux_1g_(icell) *
                (*xs_mesh_)[icell].xsmacrm()[group] * vol_[icell];

            std::cout << "Cell balance: " << b << std::endl;
        }
        std::cout << std::endl;
    }

    void SnSweeper::output( H5Node &node ) const {
        auto dims = mesh_.dimensions();
        std::reverse( dims.begin(), dims.end() );

        // Make a group in the file to store the flux
        node.create_group("flux");

        ArrayB2 flux = this->get_pin_flux();
        Normalize( flux.begin(), flux.end() );

        for( int ig=0; ig<n_group_; ig++ ) {
            std::stringstream setname;
            setname << "flux/" << std::setfill('0') << std::setw(3) << ig+1;

            ArrayB1 flux_1g = flux(blitz::Range::all(), ig);

            node.write( setname.str(), flux_1g.begin(), flux_1g.end(),
                    dims);
        }

        node.write( "pin_powers", this->pin_powers() );
        ang_quad_.output( node );

        LogFile << "Sn Sweeper:" << std::endl;

        LogFile << "Boundary update: ";
        if( gs_boundary_ ) {
            LogFile << "Gauss-Seidel" << std::endl;
        } else {
            LogFile << "Jacobi" << std::endl;
        }

        LogFile << std::endl;

        xs_mesh_->output( node );
        return;
    }
} // namespace sn
} // namespace moc
<|endoftext|>


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

/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_X86_FLOATREGFILE_HH__
#define __ARCH_X86_FLOATREGFILE_HH__

#include <string>

#include "arch/x86/faults.hh"
#include "arch/x86/types.hh"
#include "arch/x86/x86_traits.hh"

class Checkpoint;

namespace X86ISA
{
    std::string getFloatRegName(RegIndex);

    const int NumFloatArchRegs = NumMMXRegs + NumXMMRegs;
    const int NumFloatRegs = NumFloatArchRegs;

    class FloatRegFile
    {
      protected:
        double regs[NumFloatRegs];

      public:
        void clear();

        FloatReg readReg(int floatReg, int width);

        FloatRegBits readRegBits(int floatReg, int width);

        Fault setReg(int floatReg, const FloatReg &val, int width);

        Fault setRegBits(int floatReg, const FloatRegBits &val, int width);

        void serialize(std::ostream &os);

        void unserialize(Checkpoint *cp, const std::string &section);
    };
}

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

/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_X86_FLOATREGFILE_HH__
#define __ARCH_X86_FLOATREGFILE_HH__

#include <string>

#include "arch/x86/faults.hh"
#include "arch/x86/types.hh"
#include "arch/x86/x86_traits.hh"

class Checkpoint;

namespace X86ISA
{
    std::string getFloatRegName(RegIndex);

    const int NumFloatArchRegs = NumMMXRegs + NumXMMRegs;
    const int NumFloatRegs = NumFloatArchRegs;

    class FloatRegFile
    {
      public:
        static const int SingleWidth = 32;
        static const int DoubleWidth = 64;
        static const int QuadWidth = 128;

      protected:
        union
        {
            uint64_t q[NumFloatRegs];
            double d[NumFloatRegs];
        };

      public:
        void clear();

        FloatReg readReg(int floatReg, int width);

        FloatRegBits readRegBits(int floatReg, int width);

        Fault setReg(int floatReg, const FloatReg &val, int width);

        Fault setRegBits(int floatReg, const FloatRegBits &val, int width);

        void serialize(std::ostream &os);

        void unserialize(Checkpoint *cp, const std::string &section);
    };
}

#endif //__ARCH_X86_FLOATREGFILE_HH__
<|endoftext|>


<commit_before>/* TTElement.hpp
 *
 * Kubo Ryosuke
 */

#ifndef SUNFISH_TT_TTSLOT_HPP__
#define SUNFISH_TT_TTSLOT_HPP__

#include "search/eval/Score.hpp"
#include "core/move/Move.hpp"
#include "core/position/Zobrist.hpp"
#include <cstdint>
#include <cassert>

// 1st quad word
#define TT_MATE_MASK   0x0000000000000001LLU
#define TT_HASH_MASK   0xfffffffffffffffeLLU

#define TT_MATE_WIDTH   1
#define TT_HASH_WIDTH  63

#define TT_MATE_SHIFT   0

static_assert(TT_MATE_WIDTH
            + TT_HASH_WIDTH <= 64, "invalid data size");
static_assert(TT_MATE_MASK == (((1LLU << TT_MATE_WIDTH) - 1LLU) << TT_MATE_SHIFT), "invalid status");
static_assert(TT_HASH_MASK == (~((1LLU << (64 - TT_HASH_WIDTH)) - 1)), "invalid status");

// 2nd quad word
#define TT_MOVE_MASK  0x000000000000ffffLLU
#define TT_SCORE_MASK 0x00000000ffff0000LLU
#define TT_STYPE_MASK 0x0000000300000000LLU
#define TT_DEPTH_MASK 0x00000ffc00000000LLU
#define TT_CSUM_MASK  0xffff000000000000LLU

#define TT_MOVE_WIDTH  16
#define TT_SCORE_WIDTH 16
#define TT_STYPE_WIDTH  2
#define TT_DEPTH_WIDTH 10
#define TT_CSUM_WIDTH  16

#define TT_MOVE_SHIFT  0
#define TT_SCORE_SHIFT (TT_MOVE_SHIFT + TT_MOVE_WIDTH)
#define TT_STYPE_SHIFT (TT_SCORE_SHIFT + TT_SCORE_WIDTH)
#define TT_DEPTH_SHIFT (TT_STYPE_SHIFT + TT_STYPE_WIDTH)

static_assert(TT_MOVE_WIDTH
            + TT_SCORE_WIDTH
            + TT_STYPE_WIDTH
            + TT_DEPTH_WIDTH
            + TT_CSUM_WIDTH <= 64, "invalid data size");
static_assert(TT_MOVE_MASK  == (((1LLU << TT_MOVE_WIDTH) - 1) << TT_MOVE_SHIFT), "invalid status");
static_assert(TT_SCORE_MASK == (((1LLU << TT_SCORE_WIDTH) - 1) << TT_SCORE_SHIFT), "invalid status");
static_assert(TT_STYPE_MASK == (((1LLU << TT_STYPE_WIDTH) - 1) << TT_STYPE_SHIFT), "invalid status");
static_assert(TT_DEPTH_MASK == (((1LLU << TT_DEPTH_WIDTH) - 1) << TT_DEPTH_SHIFT), "invalid status");
static_assert(TT_CSUM_MASK  == (~((1LLU << (64 - TT_CSUM_WIDTH)) - 1)), "invalid status");

static_assert(sizeof(sunfish::Score::RawType) == 2, "invalid data size");

static_assert(TT_CSUM_WIDTH == 16, "invalid data size");
static_assert(TT_CSUM_MASK == 0xffff000000000000LLU, "invalid data size");

namespace sunfish {

enum class TTScoreType : int {
  Exact = 0,
  Upper, /* = 1 */
  Lower, /* = 2 */
  None, /* = 3 */
};

class TTElement {
public:

  using QuadWord = uint64_t;

private:

  QuadWord w1_;
  QuadWord w2_;

  bool update(Zobrist::Type newHash,
              Score newScore,
              TTScoreType newScoreType,
              int newDepth,
              int ply,
              Move move,
              bool mateThreat);

  QuadWord calcCheckSum() const {
    return
      (
        (w1_) ^
        (w1_ << 16) ^
        (w1_ << 32) ^
        (w1_ << 48) ^
        (w2_ << 16) ^
        (w2_ << 32) ^
        (w2_ << 48)
      );
  }

public:
  TTElement() :
      w1_(0),
      w2_(TT_CSUM_MASK) {
  }

  bool update(Zobrist::Type newHash,
              Score alpha,
              Score beta,
              Score newScore,
              int newDepth, int ply,
              const Move& move,
              bool mateThreat) {
    TTScoreType newScoreType;
    if (newScore >= beta) {
      newScoreType = TTScoreType::Lower;
    } else if (newScore <= alpha) {
      newScoreType = TTScoreType::Upper;
    } else {
      newScoreType = TTScoreType::Exact;
    }

    return update(newHash,
                  newScore,
                  newScoreType,
                  newDepth,
                  ply,
                  move,
                  mateThreat);
  }

  void updatePV(Zobrist::Type newHash,
                Score newScore,
                int newDepth,
                Move move);

  bool isLive() const {
    return ((w2_ ^ calcCheckSum()) & TT_CSUM_MASK) == 0LLU;
  }

  bool checkHash(Zobrist::Type hash) const {
    return ((w1_ ^ hash) & TT_HASH_MASK) == 0LLU && isLive();
  }

  Zobrist::Type hash() const {
    return w1_ & TT_HASH_MASK;
  }

  Score score(int ply) const {
    auto data = (w2_ & TT_SCORE_MASK) >> TT_SCORE_SHIFT;
    auto u16 = static_cast<uint16_t>(data);
    auto rawValue = static_cast<Score::RawType>(u16);
    Score s(rawValue);

    TTScoreType st = scoreType();
    ASSERT(st == TTScoreType::None || s >= -Score::infinity());
    ASSERT(st == TTScoreType::None || s <= Score::infinity());

    if (s >= Score::mate()) {
      if (st == TTScoreType::Lower) { return s - ply; }
    } else if (s <= -Score::mate()) {
      if (st == TTScoreType::Upper) { return s + ply; }
    }

    return s;
  }

  TTScoreType scoreType() const {
    auto data = (w2_ & TT_STYPE_MASK) >> TT_STYPE_SHIFT;
    return static_cast<TTScoreType>(data);
  }

  int depth() const {
    auto data = (w2_ & TT_DEPTH_MASK) >> TT_DEPTH_SHIFT;
    return static_cast<int>(data);
  }

  Move move() const {
    auto data = (w2_ & TT_MOVE_MASK) >> TT_MOVE_SHIFT;
    auto rawValue = static_cast<Move::RawType16>(data);
    return Move::deserialize(rawValue);
  }

  bool isMateThreat() const {
    return w1_ & TT_MATE_MASK;
  }

};

} // namespace sunfish

inline std::ostream& operator<<(std::ostream& os, sunfish::TTScoreType scrState) {
  switch (scrState) {
  case sunfish::TTScoreType::Exact:
    os << "Exact";
    break;
  case sunfish::TTScoreType::Upper:
    os << "Upper";
    break;
  case sunfish::TTScoreType::Lower:
    os << "Lower";
    break;
  case sunfish::TTScoreType::None:
    os << "None";
    break;
  }
  return os;
}

#endif // SUNFISH_TT_TTSLOT_HPP__
<commit_msg>Fix TT<commit_after>/* TTElement.hpp
 *
 * Kubo Ryosuke
 */

#ifndef SUNFISH_TT_TTSLOT_HPP__
#define SUNFISH_TT_TTSLOT_HPP__

#include "search/eval/Score.hpp"
#include "core/move/Move.hpp"
#include "core/position/Zobrist.hpp"
#include <cstdint>
#include <cassert>

// 1st quad word
#define TT_MATE_MASK   0x8000000000000000LLU
#define TT_HASH_MASK   0x7fffffffffffffffLLU

#define TT_HASH_WIDTH  63
#define TT_MATE_WIDTH   1

#define TT_MATE_SHIFT  63

static_assert(TT_MATE_WIDTH
            + TT_HASH_WIDTH <= 64, "invalid data size");
static_assert(TT_MATE_MASK == (((1LLU << TT_MATE_WIDTH) - 1LLU) << TT_MATE_SHIFT), "invalid status");
static_assert(TT_HASH_MASK == ~TT_MATE_MASK, "invalid status");

// 2nd quad word
#define TT_MOVE_MASK  0x000000000000ffffLLU
#define TT_SCORE_MASK 0x00000000ffff0000LLU
#define TT_STYPE_MASK 0x0000000300000000LLU
#define TT_DEPTH_MASK 0x00000ffc00000000LLU
#define TT_CSUM_MASK  0xffff000000000000LLU

#define TT_MOVE_WIDTH  16
#define TT_SCORE_WIDTH 16
#define TT_STYPE_WIDTH  2
#define TT_DEPTH_WIDTH 10
#define TT_CSUM_WIDTH  16

#define TT_MOVE_SHIFT  0
#define TT_SCORE_SHIFT (TT_MOVE_SHIFT + TT_MOVE_WIDTH)
#define TT_STYPE_SHIFT (TT_SCORE_SHIFT + TT_SCORE_WIDTH)
#define TT_DEPTH_SHIFT (TT_STYPE_SHIFT + TT_STYPE_WIDTH)

static_assert(TT_MOVE_WIDTH
            + TT_SCORE_WIDTH
            + TT_STYPE_WIDTH
            + TT_DEPTH_WIDTH
            + TT_CSUM_WIDTH <= 64, "invalid data size");
static_assert(TT_MOVE_MASK  == (((1LLU << TT_MOVE_WIDTH) - 1) << TT_MOVE_SHIFT), "invalid status");
static_assert(TT_SCORE_MASK == (((1LLU << TT_SCORE_WIDTH) - 1) << TT_SCORE_SHIFT), "invalid status");
static_assert(TT_STYPE_MASK == (((1LLU << TT_STYPE_WIDTH) - 1) << TT_STYPE_SHIFT), "invalid status");
static_assert(TT_DEPTH_MASK == (((1LLU << TT_DEPTH_WIDTH) - 1) << TT_DEPTH_SHIFT), "invalid status");
static_assert(TT_CSUM_MASK  == (~((1LLU << (64 - TT_CSUM_WIDTH)) - 1)), "invalid status");

static_assert(sizeof(sunfish::Score::RawType) == 2, "invalid data size");

static_assert(TT_CSUM_WIDTH == 16, "invalid data size");
static_assert(TT_CSUM_MASK == 0xffff000000000000LLU, "invalid data size");

namespace sunfish {

enum class TTScoreType : int {
  Exact = 0,
  Upper, /* = 1 */
  Lower, /* = 2 */
  None, /* = 3 */
};

class TTElement {
public:

  using QuadWord = uint64_t;

private:

  QuadWord w1_;
  QuadWord w2_;

  bool update(Zobrist::Type newHash,
              Score newScore,
              TTScoreType newScoreType,
              int newDepth,
              int ply,
              Move move,
              bool mateThreat);

  QuadWord calcCheckSum() const {
    return
      (
        (w1_) ^
        (w1_ << 16) ^
        (w1_ << 32) ^
        (w1_ << 48) ^
        (w2_ << 16) ^
        (w2_ << 32) ^
        (w2_ << 48)
      );
  }

public:
  TTElement() :
      w1_(0),
      w2_(TT_CSUM_MASK) {
  }

  bool update(Zobrist::Type newHash,
              Score alpha,
              Score beta,
              Score newScore,
              int newDepth, int ply,
              const Move& move,
              bool mateThreat) {
    TTScoreType newScoreType;
    if (newScore >= beta) {
      newScoreType = TTScoreType::Lower;
    } else if (newScore <= alpha) {
      newScoreType = TTScoreType::Upper;
    } else {
      newScoreType = TTScoreType::Exact;
    }

    return update(newHash,
                  newScore,
                  newScoreType,
                  newDepth,
                  ply,
                  move,
                  mateThreat);
  }

  void updatePV(Zobrist::Type newHash,
                Score newScore,
                int newDepth,
                Move move);

  bool isLive() const {
    return ((w2_ ^ calcCheckSum()) & TT_CSUM_MASK) == 0LLU;
  }

  bool checkHash(Zobrist::Type hash) const {
    return ((w1_ ^ hash) & TT_HASH_MASK) == 0LLU && isLive();
  }

  Zobrist::Type hash() const {
    return w1_ & TT_HASH_MASK;
  }

  Score score(int ply) const {
    auto data = (w2_ & TT_SCORE_MASK) >> TT_SCORE_SHIFT;
    auto u16 = static_cast<uint16_t>(data);
    auto rawValue = static_cast<Score::RawType>(u16);
    Score s(rawValue);

    TTScoreType st = scoreType();
    ASSERT(st == TTScoreType::None || s >= -Score::infinity());
    ASSERT(st == TTScoreType::None || s <= Score::infinity());

    if (s >= Score::mate()) {
      if (st == TTScoreType::Lower) { return s - ply; }
    } else if (s <= -Score::mate()) {
      if (st == TTScoreType::Upper) { return s + ply; }
    }

    return s;
  }

  TTScoreType scoreType() const {
    auto data = (w2_ & TT_STYPE_MASK) >> TT_STYPE_SHIFT;
    return static_cast<TTScoreType>(data);
  }

  int depth() const {
    auto data = (w2_ & TT_DEPTH_MASK) >> TT_DEPTH_SHIFT;
    return static_cast<int>(data);
  }

  Move move() const {
    auto data = (w2_ & TT_MOVE_MASK) >> TT_MOVE_SHIFT;
    auto rawValue = static_cast<Move::RawType16>(data);
    return Move::deserialize(rawValue);
  }

  bool isMateThreat() const {
    return w1_ & TT_MATE_MASK;
  }

};

} // namespace sunfish

inline std::ostream& operator<<(std::ostream& os, sunfish::TTScoreType scrState) {
  switch (scrState) {
  case sunfish::TTScoreType::Exact:
    os << "Exact";
    break;
  case sunfish::TTScoreType::Upper:
    os << "Upper";
    break;
  case sunfish::TTScoreType::Lower:
    os << "Lower";
    break;
  case sunfish::TTScoreType::None:
    os << "None";
    break;
  }
  return os;
}

#endif // SUNFISH_TT_TTSLOT_HPP__
<|endoftext|>


<commit_before>#include "update_status_effects.h"
#include "../SCBW/api.h"
#include "../SCBW/enumerations.h"
#include "../SCBW/scbwdata.h"
#include "irradiate.h"
#include <algorithm>

namespace {
//Helper functions that should be used only in this file
u8 getAcidSporeOverlayAdjustment(const CUnit* const unit);
} //unnamed namespace

namespace hooks {

//Detour for UpdateStatusEffects() (AKA RestoreAllUnitStats())
//Original function address: 0x00492F70 (SCBW 1.16.1)
//Note: this function is called every 8 ticks (when unit->cycleCounter reaches 8 == 0)
void updateStatusEffectsHook(CUnit *unit) {
  if (unit->stasisTimer) {
    unit->stasisTimer--;
    if (unit->stasisTimer == 0)
      unit->removeStasisField();
  }

  if (unit->stimTimer) {
    unit->stimTimer--;
    if (unit->stimTimer == 0) {
      unit->updateSpeed();
      unit->removeOverlay(IMAGE_STIM_PACKS_EFFECT); //Remove Stim Packs effect overlay
    }
  }

  if (unit->ensnareTimer) {
    unit->ensnareTimer--;
    if (unit->ensnareTimer == 0) {
      unit->removeOverlay(ImageId::EnsnareOverlay_Small, ImageId::EnsnareOverlay_Large);
      unit->updateSpeed();
    }
  }

  if (unit->defensiveMatrixTimer) {
    unit->defensiveMatrixTimer--;
    if (unit->defensiveMatrixTimer == 0) {
      unit->reduceDefensiveMatrixHp(unit->defensiveMatrixHp);
    }
  }

  if (unit->irradiateTimer) {
    unit->irradiateTimer--;
    doIrradiateDamage(unit);
    if (unit->irradiateTimer == 0) {
      unit->removeOverlay(ImageId::Irradiate_Small, ImageId::Irradiate_Large);
      unit->irradiatedBy = NULL;
      unit->irradiatePlayerId = 8;
    }
  }

  if (unit->lockdownTimer) {
    unit->lockdownTimer--;
    if (unit->lockdownTimer == 0)
      unit->removeLockdown();
  }

  if (unit->maelstromTimer) {
    unit->maelstromTimer--;
    if (unit->maelstromTimer == 0)
      unit->removeMaelstrom();
  }

  if (unit->plagueTimer) {
    unit->plagueTimer--;
    if (!(unit->status & UnitStatus::Invincible)) {
      //Try to reduce the unit's HP to 1/256 without killing it
      const s32 damage = (Weapon::DamageAmount[WeaponId::Plague] << 8) / 75;
      if (unit->hitPoints > 1)
        unit->damageHp(std::min(damage, unit->hitPoints - 1));
    }
    if (unit->plagueTimer == 0)
      unit->removeOverlay(ImageId::PlagueOverlay_Small, ImageId::PlagueOverlay_Large);
  }

  if (unit->isUnderStorm)
    unit->isUnderStorm--;

  //Add Ocular Implants effect overlay
  if (unit->isBlind) {
    if (!unit->getOverlay(IMAGE_OCULAR_IMPLANTS_EFFECT))
      unit->sprite->createOverlay(IMAGE_OCULAR_IMPLANTS_EFFECT, 0, -20);
  }

  u8 previousAcidSporeCount = unit->acidSporeCount;
  for (int i = 0; i <= 8; ++i) {
    if (unit->acidSporeTime[i]) {
      unit->acidSporeTime[i]--;
      if (unit->acidSporeTime[i] == 0)
        unit->acidSporeCount--;
    }
  }
  if (unit->acidSporeCount) {
    u32 acidOverlayId = getAcidSporeOverlayAdjustment(unit) + ImageId::AcidSpores_1_Overlay_Small;
    if (!unit->getOverlay(acidOverlayId)) {
      unit->removeOverlay(ImageId::AcidSpores_1_Overlay_Small, ImageId::AcidSpores_6_9_Overlay_Large);
      if (unit->subunit)
        unit = unit->subunit;
      unit->sprite->createTopOverlay(acidOverlayId);
    }
  }
  else if (previousAcidSporeCount) {
    unit->removeOverlay(ImageId::AcidSpores_1_Overlay_Small, ImageId::AcidSpores_6_9_Overlay_Large);
  }
}

} //hooks

namespace {
/**** Helper function definitions. Do not change anything below this! ****/

u8 getAcidSporeOverlayAdjustment(const CUnit* const unit) {
  u8 adjustment = unit->acidSporeCount >> 1;
  return (adjustment < 3 ? adjustment : 3)
          + 4 * scbw::getUnitOverlayAdjustment(unit);
}

} //unnamed namespace
<commit_msg>Display the Ocular Implants graphics effect over the Siege Tank's turret.<commit_after>#include "update_status_effects.h"
#include "../SCBW/api.h"
#include "../SCBW/enumerations.h"
#include "../SCBW/scbwdata.h"
#include "irradiate.h"
#include <algorithm>

namespace {
//Helper functions that should be used only in this file
u8 getAcidSporeOverlayAdjustment(const CUnit* const unit);
} //unnamed namespace

namespace hooks {

//Detour for UpdateStatusEffects() (AKA RestoreAllUnitStats())
//Original function address: 0x00492F70 (SCBW 1.16.1)
//Note: this function is called every 8 ticks (when unit->cycleCounter reaches 8 == 0)
void updateStatusEffectsHook(CUnit *unit) {
  if (unit->stasisTimer) {
    unit->stasisTimer--;
    if (unit->stasisTimer == 0)
      unit->removeStasisField();
  }

  if (unit->stimTimer) {
    unit->stimTimer--;
    if (unit->stimTimer == 0) {
      unit->updateSpeed();
      unit->removeOverlay(IMAGE_STIM_PACKS_EFFECT); //Remove Stim Packs effect overlay
    }
  }

  if (unit->ensnareTimer) {
    unit->ensnareTimer--;
    if (unit->ensnareTimer == 0) {
      unit->removeOverlay(ImageId::EnsnareOverlay_Small, ImageId::EnsnareOverlay_Large);
      unit->updateSpeed();
    }
  }

  if (unit->defensiveMatrixTimer) {
    unit->defensiveMatrixTimer--;
    if (unit->defensiveMatrixTimer == 0) {
      unit->reduceDefensiveMatrixHp(unit->defensiveMatrixHp);
    }
  }

  if (unit->irradiateTimer) {
    unit->irradiateTimer--;
    doIrradiateDamage(unit);
    if (unit->irradiateTimer == 0) {
      unit->removeOverlay(ImageId::Irradiate_Small, ImageId::Irradiate_Large);
      unit->irradiatedBy = NULL;
      unit->irradiatePlayerId = 8;
    }
  }

  if (unit->lockdownTimer) {
    unit->lockdownTimer--;
    if (unit->lockdownTimer == 0)
      unit->removeLockdown();
  }

  if (unit->maelstromTimer) {
    unit->maelstromTimer--;
    if (unit->maelstromTimer == 0)
      unit->removeMaelstrom();
  }

  if (unit->plagueTimer) {
    unit->plagueTimer--;
    if (!(unit->status & UnitStatus::Invincible)) {
      //Try to reduce the unit's HP to 1/256 without killing it
      const s32 damage = (Weapon::DamageAmount[WeaponId::Plague] << 8) / 75;
      if (unit->hitPoints > 1)
        unit->damageHp(std::min(damage, unit->hitPoints - 1));
    }
    if (unit->plagueTimer == 0)
      unit->removeOverlay(ImageId::PlagueOverlay_Small, ImageId::PlagueOverlay_Large);
  }

  if (unit->isUnderStorm)
    unit->isUnderStorm--;

  //Add Ocular Implants effect overlay
  if (unit->isBlind) {
    //Display the sprite over the Siege Tank's turret
    CUnit *theUnit = unit->subunit ? unit->subunit : unit;
    if (!theUnit->getOverlay(IMAGE_OCULAR_IMPLANTS_EFFECT))
      theUnit->sprite->createOverlay(IMAGE_OCULAR_IMPLANTS_EFFECT, 0, -20);
  }

  u8 previousAcidSporeCount = unit->acidSporeCount;
  for (int i = 0; i <= 8; ++i) {
    if (unit->acidSporeTime[i]) {
      unit->acidSporeTime[i]--;
      if (unit->acidSporeTime[i] == 0)
        unit->acidSporeCount--;
    }
  }
  if (unit->acidSporeCount) {
    u32 acidOverlayId = getAcidSporeOverlayAdjustment(unit) + ImageId::AcidSpores_1_Overlay_Small;
    if (!unit->getOverlay(acidOverlayId)) {
      unit->removeOverlay(ImageId::AcidSpores_1_Overlay_Small, ImageId::AcidSpores_6_9_Overlay_Large);
      if (unit->subunit)
        unit = unit->subunit;
      unit->sprite->createTopOverlay(acidOverlayId);
    }
  }
  else if (previousAcidSporeCount) {
    unit->removeOverlay(ImageId::AcidSpores_1_Overlay_Small, ImageId::AcidSpores_6_9_Overlay_Large);
  }
}

} //hooks

namespace {
/**** Helper function definitions. Do not change anything below this! ****/

u8 getAcidSporeOverlayAdjustment(const CUnit* const unit) {
  u8 adjustment = unit->acidSporeCount >> 1;
  return (adjustment < 3 ? adjustment : 3)
          + 4 * scbw::getUnitOverlayAdjustment(unit);
}

} //unnamed namespace
<|endoftext|>