<commit_before>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCORO_DETAIL_WIN32_OVERLAPPED_OPERATION_HPP_INCLUDED
#define CPPCORO_DETAIL_WIN32_OVERLAPPED_OPERATION_HPP_INCLUDED

#include <cppcoro/cancellation_registration.hpp>
#include <cppcoro/cancellation_token.hpp>
#include <cppcoro/operation_cancelled.hpp>

#include <cppcoro/detail/win32.hpp>

#include <optional>
#include <system_error>
#include <experimental/coroutine>
#include <cassert>

namespace cppcoro
{
	namespace detail
	{
		class win32_overlapped_operation_base
			: protected detail::win32::io_state
		{
		protected:

			win32_overlapped_operation_base(
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			win32_overlapped_operation_base(
				void* pointer,
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(pointer, callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			win32_overlapped_operation_base(
				std::uint64_t offset,
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(offset, callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			_OVERLAPPED* get_overlapped() noexcept
			{
				return reinterpret_cast<_OVERLAPPED*>(
					static_cast<detail::win32::overlapped*>(this));
			}

			std::size_t get_result()
			{
				if (m_errorCode != 0)
				{
					throw std::system_error{
						static_cast<int>(m_errorCode),
						std::system_category()
					};
				}

				return m_numberOfBytesTransferred;
			}

			detail::win32::dword_t m_errorCode;
			detail::win32::dword_t m_numberOfBytesTransferred;

		};

		template<typename OPERATION>
		class win32_overlapped_operation
			: protected win32_overlapped_operation_base
		{
		protected:

			win32_overlapped_operation() noexcept
				: win32_overlapped_operation_base(
					&win32_overlapped_operation::on_operation_completed)
			{}

			win32_overlapped_operation(void* pointer) noexcept
				: win32_overlapped_operation_base(
					pointer,
					&win32_overlapped_operation::on_operation_completed)
			{}

			win32_overlapped_operation(std::uint64_t offset) noexcept
				: win32_overlapped_operation_base(
					offset,
					&win32_overlapped_operation::on_operation_completed)
			{}

		public:

			bool await_ready() const noexcept { return false; }

			bool await_suspend(std::experimental::coroutine_handle<> awaitingCoroutine)
			{
				static_assert(std::is_base_of_v<win32_overlapped_operation, OPERATION>);

				m_awaitingCoroutine = awaitingCoroutine;
				return static_cast<OPERATION*>(this)->try_start();
			}

			decltype(auto) await_resume()
			{
				return static_cast<OPERATION*>(this)->get_result();
			}

		private:

			static void on_operation_completed(
				detail::win32::io_state* ioState,
				detail::win32::dword_t errorCode,
				detail::win32::dword_t numberOfBytesTransferred,
				[[maybe_unused]] detail::win32::ulongptr_t completionKey) noexcept
			{
				auto* operation = static_cast<win32_overlapped_operation*>(ioState);
				operation->m_errorCode = errorCode;
				operation->m_numberOfBytesTransferred = numberOfBytesTransferred;
				operation->m_awaitingCoroutine.resume();
			}

			std::experimental::coroutine_handle<> m_awaitingCoroutine;

		};

		template<typename OPERATION>
		class win32_overlapped_operation_cancellable
			: protected win32_overlapped_operation_base
		{
			// ERROR_OPERATION_ABORTED value from <Windows.h>
			static constexpr detail::win32::dword_t error_operation_aborted = 995L;

		protected:

			win32_overlapped_operation_cancellable(cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(&win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				void* pointer,
				cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(pointer, &win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				std::uint64_t offset,
				cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(offset, &win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				win32_overlapped_operation_cancellable&& other) noexcept
				: win32_overlapped_operation_base(std::move(other))
				, m_state(other.m_state.load(std::memory_order_relaxed))
				, m_cancellationToken(std::move(other.m_cancellationToken))
				, m_errorCode(other.m_errorCode)
				, m_numberOfBytesTransferred(other.m_numberOfBytesTransferred)
			{
			}

		public:

			bool await_ready() const noexcept
			{
				return m_state.load(std::memory_order_relaxed) == state::completed;
			}

			bool await_suspend(std::experimental::coroutine_handle<> awaitingCoroutine)
			{
				static_assert(std::is_base_of_v<win32_overlapped_operation_cancellable, OPERATION>);

				m_awaitingCoroutine = awaitingCoroutine;

				// TRICKY: Register cancellation callback before starting the operation
				// in case the callback registration throws due to insufficient
				// memory. We need to make sure that the logic that occurs after
				// starting the operation is noexcept, otherwise we run into the
				// problem of not being able to cancel the started operation and
				// the dilemma of what to do with the exception.
				//
				// However, doing this means that the cancellation callback may run
				// prior to returning below so in the case that cancellation may
				// occur we defer setting the state to 'started' until after
				// the operation has finished starting. The cancellation callback
				// will only attempt to request cancellation of the operation with
				// CancelIoEx() once the state has been set to 'started'.
				const bool canBeCancelled = m_cancellationToken.can_be_cancelled();
				if (canBeCancelled)
				{
					m_cancellationCallback.emplace(
						std::move(m_cancellationToken),
						[this] { this->on_cancellation_requested(); });
				}
				else
				{
					m_state.store(state::started, std::memory_order_relaxed);
				}

				// Now start the operation.
				const bool willCompleteAsynchronously = static_cast<OPERATION*>(this)->try_start();
				if (!willCompleteAsynchronously)
				{
					// Operation completed synchronously, resume awaiting coroutine immediately.
					return false;
				}

				if (canBeCancelled)
				{
					// Need to flag that the operation has finished starting now.

					// However, the operation may have completed concurrently on
					// another thread, transitioning directly from not_started -> complete.
					// Or it may have had the cancellation callback execute and transition
					// from not_started -> cancellation_requested. We use a compare-exchange
					// to determine a winner between these potential racing cases.
					state oldState = state::not_started;
					if (!m_state.compare_exchange_strong(
						oldState,
						state::started,
						std::memory_order_release,
						std::memory_order_acquire))
					{
						if (oldState == state::cancellation_requested)
						{
							// Request the operation be cancelled.
							// Note that it may have already completed on a background
							// thread by now so this request for cancellation may end up
							// being ignored.
							static_cast<OPERATION*>(this)->cancel();

							if (!m_state.compare_exchange_strong(
								oldState,
								state::started,
								std::memory_order_release,
								std::memory_order_acquire))
							{
								assert(oldState == state::completed);
								return false;
							}
						}
						else
						{
							assert(oldState == state::completed);
							return false;
						}
					}
				}

				return true;
			}

			decltype(auto) await_resume()
			{
				// Free memory used by the cancellation callback now that the operation
				// has completed rather than waiting until the operation object destructs.
				// eg. If the operation is passed to when_all() then the operation object
				// may not be destructed until all of the operations complete.
				m_cancellationCallback.reset();

				if (m_errorCode == error_operation_aborted)
				{
					throw operation_cancelled{};
				}

				return static_cast<OPERATION*>(this)->get_result();
			}

		private:

			enum class state
			{
				not_started,
				started,
				cancellation_requested,
				completed
			};

			void on_cancellation_requested() noexcept
			{
				auto oldState = m_state.load(std::memory_order_acquire);
				if (oldState == state::not_started)
				{
					// This callback is running concurrently with await_suspend().
					// The call to start the operation may not have returned yet so
					// we can't safely request cancellation of it. Instead we try to
					// notify the await_suspend() thread by transitioning the state
					// to state::cancellation_requested so that the await_suspend()
					// thread can request cancellation after it has finished starting
					// the operation.
					const bool transferredCancelResponsibility =
						m_state.compare_exchange_strong(
							oldState,
							state::cancellation_requested,
							std::memory_order_release,
							std::memory_order_acquire);
					if (transferredCancelResponsibility)
					{
						return;
					}
				}

				// No point requesting cancellation if the operation has already completed.
				if (oldState != state::completed)
				{
					static_cast<OPERATION*>(this)->cancel();
				}
			}

			static void on_operation_completed(
				detail::win32::io_state* ioState,
				detail::win32::dword_t errorCode,
				detail::win32::dword_t numberOfBytesTransferred,
				[[maybe_unused]] detail::win32::ulongptr_t completionKey) noexcept
			{
				auto* operation = static_cast<win32_overlapped_operation_cancellable*>(ioState);

				operation->m_errorCode = errorCode;
				operation->m_numberOfBytesTransferred = numberOfBytesTransferred;

				auto state = operation->m_state.load(std::memory_order_acquire);
				if (state == state::started)
				{
					operation->m_state.store(state::completed, std::memory_order_relaxed);
					operation->m_awaitingCoroutine.resume();
				}
				else
				{
					// We are racing with await_suspend() call suspending.
					// Try to mark it as completed using an atomic exchange and look
					// at the previous value to determine whether the coroutine suspended
					// first (in which case we resume it now) or we marked it as completed
					// first (in which case await_suspend() will return false and immediately
					// resume the coroutine).
					state = operation->m_state.exchange(
						state::completed,
						std::memory_order_acq_rel);
					if (state == state::started)
					{
						// The await_suspend() method returned (or will return) 'true' and so
						// we need to resume the coroutine.
						operation->m_awaitingCoroutine.resume();
					}
				}
			}

			std::atomic<state> m_state;
			cppcoro::cancellation_token m_cancellationToken;
			std::optional<cppcoro::cancellation_registration> m_cancellationCallback;
			std::experimental::coroutine_handle<> m_awaitingCoroutine;

		};
	}
}

#endif
<commit_msg>Fixed move constructor for win32_overlapped_operation_cancellable. (#80)<commit_after>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCORO_DETAIL_WIN32_OVERLAPPED_OPERATION_HPP_INCLUDED
#define CPPCORO_DETAIL_WIN32_OVERLAPPED_OPERATION_HPP_INCLUDED

#include <cppcoro/cancellation_registration.hpp>
#include <cppcoro/cancellation_token.hpp>
#include <cppcoro/operation_cancelled.hpp>

#include <cppcoro/detail/win32.hpp>

#include <optional>
#include <system_error>
#include <experimental/coroutine>
#include <cassert>

namespace cppcoro
{
	namespace detail
	{
		class win32_overlapped_operation_base
			: protected detail::win32::io_state
		{
		protected:

			win32_overlapped_operation_base(
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			win32_overlapped_operation_base(
				void* pointer,
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(pointer, callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			win32_overlapped_operation_base(
				std::uint64_t offset,
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(offset, callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			_OVERLAPPED* get_overlapped() noexcept
			{
				return reinterpret_cast<_OVERLAPPED*>(
					static_cast<detail::win32::overlapped*>(this));
			}

			std::size_t get_result()
			{
				if (m_errorCode != 0)
				{
					throw std::system_error{
						static_cast<int>(m_errorCode),
						std::system_category()
					};
				}

				return m_numberOfBytesTransferred;
			}

			detail::win32::dword_t m_errorCode;
			detail::win32::dword_t m_numberOfBytesTransferred;

		};

		template<typename OPERATION>
		class win32_overlapped_operation
			: protected win32_overlapped_operation_base
		{
		protected:

			win32_overlapped_operation() noexcept
				: win32_overlapped_operation_base(
					&win32_overlapped_operation::on_operation_completed)
			{}

			win32_overlapped_operation(void* pointer) noexcept
				: win32_overlapped_operation_base(
					pointer,
					&win32_overlapped_operation::on_operation_completed)
			{}

			win32_overlapped_operation(std::uint64_t offset) noexcept
				: win32_overlapped_operation_base(
					offset,
					&win32_overlapped_operation::on_operation_completed)
			{}

		public:

			bool await_ready() const noexcept { return false; }

			bool await_suspend(std::experimental::coroutine_handle<> awaitingCoroutine)
			{
				static_assert(std::is_base_of_v<win32_overlapped_operation, OPERATION>);

				m_awaitingCoroutine = awaitingCoroutine;
				return static_cast<OPERATION*>(this)->try_start();
			}

			decltype(auto) await_resume()
			{
				return static_cast<OPERATION*>(this)->get_result();
			}

		private:

			static void on_operation_completed(
				detail::win32::io_state* ioState,
				detail::win32::dword_t errorCode,
				detail::win32::dword_t numberOfBytesTransferred,
				[[maybe_unused]] detail::win32::ulongptr_t completionKey) noexcept
			{
				auto* operation = static_cast<win32_overlapped_operation*>(ioState);
				operation->m_errorCode = errorCode;
				operation->m_numberOfBytesTransferred = numberOfBytesTransferred;
				operation->m_awaitingCoroutine.resume();
			}

			std::experimental::coroutine_handle<> m_awaitingCoroutine;

		};

		template<typename OPERATION>
		class win32_overlapped_operation_cancellable
			: protected win32_overlapped_operation_base
		{
			// ERROR_OPERATION_ABORTED value from <Windows.h>
			static constexpr detail::win32::dword_t error_operation_aborted = 995L;

		protected:

			win32_overlapped_operation_cancellable(cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(&win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				void* pointer,
				cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(pointer, &win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				std::uint64_t offset,
				cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(offset, &win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				win32_overlapped_operation_cancellable&& other) noexcept
				: win32_overlapped_operation_base(std::move(other))
				, m_state(other.m_state.load(std::memory_order_relaxed))
				, m_cancellationToken(std::move(other.m_cancellationToken))
			{
				assert(m_errorCode == other.m_errorCode);
				assert(m_numberOfBytesTransferred == other.m_numberOfBytesTransferred);
			}

		public:

			bool await_ready() const noexcept
			{
				return m_state.load(std::memory_order_relaxed) == state::completed;
			}

			bool await_suspend(std::experimental::coroutine_handle<> awaitingCoroutine)
			{
				static_assert(std::is_base_of_v<win32_overlapped_operation_cancellable, OPERATION>);

				m_awaitingCoroutine = awaitingCoroutine;

				// TRICKY: Register cancellation callback before starting the operation
				// in case the callback registration throws due to insufficient
				// memory. We need to make sure that the logic that occurs after
				// starting the operation is noexcept, otherwise we run into the
				// problem of not being able to cancel the started operation and
				// the dilemma of what to do with the exception.
				//
				// However, doing this means that the cancellation callback may run
				// prior to returning below so in the case that cancellation may
				// occur we defer setting the state to 'started' until after
				// the operation has finished starting. The cancellation callback
				// will only attempt to request cancellation of the operation with
				// CancelIoEx() once the state has been set to 'started'.
				const bool canBeCancelled = m_cancellationToken.can_be_cancelled();
				if (canBeCancelled)
				{
					m_cancellationCallback.emplace(
						std::move(m_cancellationToken),
						[this] { this->on_cancellation_requested(); });
				}
				else
				{
					m_state.store(state::started, std::memory_order_relaxed);
				}

				// Now start the operation.
				const bool willCompleteAsynchronously = static_cast<OPERATION*>(this)->try_start();
				if (!willCompleteAsynchronously)
				{
					// Operation completed synchronously, resume awaiting coroutine immediately.
					return false;
				}

				if (canBeCancelled)
				{
					// Need to flag that the operation has finished starting now.

					// However, the operation may have completed concurrently on
					// another thread, transitioning directly from not_started -> complete.
					// Or it may have had the cancellation callback execute and transition
					// from not_started -> cancellation_requested. We use a compare-exchange
					// to determine a winner between these potential racing cases.
					state oldState = state::not_started;
					if (!m_state.compare_exchange_strong(
						oldState,
						state::started,
						std::memory_order_release,
						std::memory_order_acquire))
					{
						if (oldState == state::cancellation_requested)
						{
							// Request the operation be cancelled.
							// Note that it may have already completed on a background
							// thread by now so this request for cancellation may end up
							// being ignored.
							static_cast<OPERATION*>(this)->cancel();

							if (!m_state.compare_exchange_strong(
								oldState,
								state::started,
								std::memory_order_release,
								std::memory_order_acquire))
							{
								assert(oldState == state::completed);
								return false;
							}
						}
						else
						{
							assert(oldState == state::completed);
							return false;
						}
					}
				}

				return true;
			}

			decltype(auto) await_resume()
			{
				// Free memory used by the cancellation callback now that the operation
				// has completed rather than waiting until the operation object destructs.
				// eg. If the operation is passed to when_all() then the operation object
				// may not be destructed until all of the operations complete.
				m_cancellationCallback.reset();

				if (m_errorCode == error_operation_aborted)
				{
					throw operation_cancelled{};
				}

				return static_cast<OPERATION*>(this)->get_result();
			}

		private:

			enum class state
			{
				not_started,
				started,
				cancellation_requested,
				completed
			};

			void on_cancellation_requested() noexcept
			{
				auto oldState = m_state.load(std::memory_order_acquire);
				if (oldState == state::not_started)
				{
					// This callback is running concurrently with await_suspend().
					// The call to start the operation may not have returned yet so
					// we can't safely request cancellation of it. Instead we try to
					// notify the await_suspend() thread by transitioning the state
					// to state::cancellation_requested so that the await_suspend()
					// thread can request cancellation after it has finished starting
					// the operation.
					const bool transferredCancelResponsibility =
						m_state.compare_exchange_strong(
							oldState,
							state::cancellation_requested,
							std::memory_order_release,
							std::memory_order_acquire);
					if (transferredCancelResponsibility)
					{
						return;
					}
				}

				// No point requesting cancellation if the operation has already completed.
				if (oldState != state::completed)
				{
					static_cast<OPERATION*>(this)->cancel();
				}
			}

			static void on_operation_completed(
				detail::win32::io_state* ioState,
				detail::win32::dword_t errorCode,
				detail::win32::dword_t numberOfBytesTransferred,
				[[maybe_unused]] detail::win32::ulongptr_t completionKey) noexcept
			{
				auto* operation = static_cast<win32_overlapped_operation_cancellable*>(ioState);

				operation->m_errorCode = errorCode;
				operation->m_numberOfBytesTransferred = numberOfBytesTransferred;

				auto state = operation->m_state.load(std::memory_order_acquire);
				if (state == state::started)
				{
					operation->m_state.store(state::completed, std::memory_order_relaxed);
					operation->m_awaitingCoroutine.resume();
				}
				else
				{
					// We are racing with await_suspend() call suspending.
					// Try to mark it as completed using an atomic exchange and look
					// at the previous value to determine whether the coroutine suspended
					// first (in which case we resume it now) or we marked it as completed
					// first (in which case await_suspend() will return false and immediately
					// resume the coroutine).
					state = operation->m_state.exchange(
						state::completed,
						std::memory_order_acq_rel);
					if (state == state::started)
					{
						// The await_suspend() method returned (or will return) 'true' and so
						// we need to resume the coroutine.
						operation->m_awaitingCoroutine.resume();
					}
				}
			}

			std::atomic<state> m_state;
			cppcoro::cancellation_token m_cancellationToken;
			std::optional<cppcoro::cancellation_registration> m_cancellationCallback;
			std::experimental::coroutine_handle<> m_awaitingCoroutine;

		};
	}
}

#endif
<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file robust_gaussian_filter.hpp
 * \date August 2015
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__FILTER__GAUSSIAN__ROBUST_GAUSSIAN_FILTER_HPP
#define FL__FILTER__GAUSSIAN__ROBUST_GAUSSIAN_FILTER_HPP

#include <fl/util/meta.hpp>
#include <fl/util/traits.hpp>
#include <fl/filter/gaussian/gaussian_filter_nonlinear_generic.hpp>
#include <fl/filter/gaussian/sigma_point_additive_uncorrelated_update_policy.hpp>
#include <fl/filter/gaussian/sigma_point_additive_prediction_policy.hpp>
#include <fl/filter/gaussian/sigma_point_additive_update_policy.hpp>S
#include <fl/filter/gaussian/sigma_point_prediction_policy.hpp>
#include <fl/filter/gaussian/sigma_point_update_policy.hpp>

namespace fl
{

// Forward delcaration
template<
    typename StateTransitionFunction,
    typename ObservationFunction,
    typename ... Policies
> class RobustGaussianFilter;

/**
 * \internal
 * \ingroup nonlinear_gaussian_filter
 * \ingroup generic_nonlinear_gaussian_filter
 *
 * Traits for generic GaussianFilter based on quadrature (numeric integration)
 * with customizable policies, i.e implementations of the time and measurement
 * updates.
 */
template <
    typename StateTransitionFunction,
    typename ObservationFunction,
    typename ... Policies
>
struct Traits<
          RobustGaussianFilter<
              StateTransitionFunction, ObservationFunction, Policies...>>
{
    typedef typename StateTransitionFunction::State State;
    typedef typename StateTransitionFunction::Input Input;
    typedef typename ObservationFunction::Obsrv Obsrv;
    typedef Gaussian<State> Belief;
};

//template <typename Obsrv, typename State, typename FeatureFunction>
//class FeatureAugmentedObservationModel
//{
//public:

//};

/**
 * \ingroup nonlinear_gaussian_filter
 * \ingroup generic_nonlinear_gaussian_filter
 */
template<
    typename StateTransitionFunction,
    typename ObservationFunction,
    typename ... Policies
>
class RobustGaussianFilter
    : public FilterInterface<
                 RobustGaussianFilter<
                     StateTransitionFunction, ObservationFunction, Policies...>>
{
public:
    typedef typename StateTransitionFunction::State State;
    typedef typename StateTransitionFunction::Input Input;
    typedef typename ObservationFunction::Obsrv Obsrv;
    typedef Gaussian<State> Belief;

    typedef GaussianFilter<
                StateTransitionFunction, ObservationFunction, Policies...
            > BaseGaussianFilter;

public:
    /**
     * \brief Creates a RobustGaussianFilter
     */
    template <typename ... SpecializationArgs>
    RobustGaussianFilter(const StateTransitionFunction& process_model,
                         const ObservationFunction& obsrv_model,
                         SpecializationArgs&& ... args)
        : gaussian_filter_(
              process_model,
              obsrv_model,
              std::forward<SpecializationArgs>(args)...)
    { }

    /**
     * \brief Overridable default destructor
     */
    virtual ~RobustGaussianFilter() { }

    /**
     * \copydoc FilterInterface::predict
     */
    virtual void predict(const Belief& prior_belief,
                         const Input& input,
                         Belief& predicted_belief)
    {
        gaussian_filter_.predict(prior_belief, input, predicted_belief);
    }

    /**
     * \copydoc FilterInterface::update
     */
    virtual void update(const Belief& predicted_belief,
                        const Obsrv& obsrv,
                        Belief& posterior_belief)
    {
        gaussian_filter_.update(predicted_belief, obsrv, posterior_belief);
    }

public: /* factory functions */
    virtual Belief create_belief() const
    {
        // note: do not simplify!
        auto belief = gaussian_filter_.create_belief();
        return belief;
    }

public: /* accessors & mutators */
    StateTransitionFunction& process_model()
    {
        return gaussian_filter_.process_model();
    }

    ObservationFunction& obsrv_model()
    {
        return gaussian_filter_.obsrv_model();
    }

    const StateTransitionFunction& process_model() const
    {
        return gaussian_filter_.process_model();
    }

    const ObservationFunction& obsrv_model() const
    {
        return gaussian_filter_.obsrv_model();
    }

    virtual std::string name() const
    {
        return "RobustGaussianFilter<"
                + this->list_arguments(
                            gaussian_filter_.name())
                + ">";
    }

    virtual std::string description() const
    {
        return "Robust GaussianFilter with"
                + this->list_descriptions(gaussian_filter_.description());
    }

protected:
    /** \cond internal */
    BaseGaussianFilter gaussian_filter_;
    /** \endcond */
};

}

#endif
<commit_msg>minor fix<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file robust_gaussian_filter.hpp
 * \date August 2015
 * \author Jan Issac (jan.issac@gmail.com)
 */

#ifndef FL__FILTER__GAUSSIAN__ROBUST_GAUSSIAN_FILTER_HPP
#define FL__FILTER__GAUSSIAN__ROBUST_GAUSSIAN_FILTER_HPP

#include <fl/util/meta.hpp>
#include <fl/util/traits.hpp>
#include <fl/filter/gaussian/gaussian_filter_nonlinear_generic.hpp>
#include <fl/filter/gaussian/sigma_point_additive_uncorrelated_update_policy.hpp>
#include <fl/filter/gaussian/sigma_point_additive_prediction_policy.hpp>
#include <fl/filter/gaussian/sigma_point_additive_update_policy.hpp>
#include <fl/filter/gaussian/sigma_point_prediction_policy.hpp>
#include <fl/filter/gaussian/sigma_point_update_policy.hpp>

namespace fl
{

// Forward delcaration
template<
    typename StateTransitionFunction,
    typename ObservationFunction,
    typename ... Policies
> class RobustGaussianFilter;

/**
 * \internal
 * \ingroup nonlinear_gaussian_filter
 * \ingroup generic_nonlinear_gaussian_filter
 *
 * Traits for generic GaussianFilter based on quadrature (numeric integration)
 * with customizable policies, i.e implementations of the time and measurement
 * updates.
 */
template <
    typename StateTransitionFunction,
    typename ObservationFunction,
    typename ... Policies
>
struct Traits<
          RobustGaussianFilter<
              StateTransitionFunction, ObservationFunction, Policies...>>
{
    typedef typename StateTransitionFunction::State State;
    typedef typename StateTransitionFunction::Input Input;
    typedef typename ObservationFunction::Obsrv Obsrv;
    typedef Gaussian<State> Belief;
};

//template <typename Obsrv, typename State, typename FeatureFunction>
//class FeatureAugmentedObservationModel
//{
//public:

//};

/**
 * \ingroup nonlinear_gaussian_filter
 * \ingroup generic_nonlinear_gaussian_filter
 */
template<
    typename StateTransitionFunction,
    typename ObservationFunction,
    typename ... Policies
>
class RobustGaussianFilter
    : public FilterInterface<
                 RobustGaussianFilter<
                     StateTransitionFunction, ObservationFunction, Policies...>>
{
public:
    typedef typename StateTransitionFunction::State State;
    typedef typename StateTransitionFunction::Input Input;
    typedef typename ObservationFunction::Obsrv Obsrv;
    typedef Gaussian<State> Belief;

    typedef GaussianFilter<
                StateTransitionFunction, ObservationFunction, Policies...
            > BaseGaussianFilter;

public:
    /**
     * \brief Creates a RobustGaussianFilter
     */
    template <typename ... SpecializationArgs>
    RobustGaussianFilter(const StateTransitionFunction& process_model,
                         const ObservationFunction& obsrv_model,
                         SpecializationArgs&& ... args)
        : gaussian_filter_(
              process_model,
              obsrv_model,
              std::forward<SpecializationArgs>(args)...)
    { }

    /**
     * \brief Overridable default destructor
     */
    virtual ~RobustGaussianFilter() { }

    /**
     * \copydoc FilterInterface::predict
     */
    virtual void predict(const Belief& prior_belief,
                         const Input& input,
                         Belief& predicted_belief)
    {
        gaussian_filter_.predict(prior_belief, input, predicted_belief);
    }

    /**
     * \copydoc FilterInterface::update
     */
    virtual void update(const Belief& predicted_belief,
                        const Obsrv& obsrv,
                        Belief& posterior_belief)
    {
        gaussian_filter_.update(predicted_belief, obsrv, posterior_belief);
    }

public: /* factory functions */
    virtual Belief create_belief() const
    {
        // note: do not simplify!
        auto belief = gaussian_filter_.create_belief();
        return belief;
    }

public: /* accessors & mutators */
    StateTransitionFunction& process_model()
    {
        return gaussian_filter_.process_model();
    }

    ObservationFunction& obsrv_model()
    {
        return gaussian_filter_.obsrv_model();
    }

    const StateTransitionFunction& process_model() const
    {
        return gaussian_filter_.process_model();
    }

    const ObservationFunction& obsrv_model() const
    {
        return gaussian_filter_.obsrv_model();
    }

    virtual std::string name() const
    {
        return "RobustGaussianFilter<"
                + this->list_arguments(
                            gaussian_filter_.name())
                + ">";
    }

    virtual std::string description() const
    {
        return "Robust GaussianFilter with"
                + this->list_descriptions(gaussian_filter_.description());
    }

protected:
    /** \cond internal */
    BaseGaussianFilter gaussian_filter_;
    /** \endcond */
};

}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkCodecPriv.h"
#include "SkWebpCodec.h"
#include "SkTemplates.h"

// A WebP decoder on top of (subset of) libwebp
// For more information on WebP image format, and libwebp library, see:
//   https://code.google.com/speed/webp/
//   http://www.webmproject.org/code/#libwebp-webp-image-library
//   https://chromium.googlesource.com/webm/libwebp

// If moving libwebp out of skia source tree, path for webp headers must be
// updated accordingly. Here, we enforce using local copy in webp sub-directory.
#include "webp/decode.h"
#include "webp/encode.h"

bool SkWebpCodec::IsWebp(const void* buf, size_t bytesRead) {
    // WEBP starts with the following:
    // RIFFXXXXWEBPVP
    // Where XXXX is unspecified.
    const char* bytes = static_cast<const char*>(buf);
    return bytesRead >= 14 && !memcmp(bytes, "RIFF", 4) && !memcmp(&bytes[8], "WEBPVP", 6);
}

// Parse headers of RIFF container, and check for valid Webp (VP8) content.
// NOTE: This calls peek instead of read, since onGetPixels will need these
// bytes again.
static bool webp_parse_header(SkStream* stream, SkImageInfo* info) {
    unsigned char buffer[WEBP_VP8_HEADER_SIZE];
    SkASSERT(WEBP_VP8_HEADER_SIZE <= SkCodec::MinBufferedBytesNeeded());

    const size_t bytesPeeked = stream->peek(buffer, WEBP_VP8_HEADER_SIZE);
    if (bytesPeeked != WEBP_VP8_HEADER_SIZE) {
        // Use read + rewind as a backup
        if (stream->read(buffer, WEBP_VP8_HEADER_SIZE) != WEBP_VP8_HEADER_SIZE
            || !stream->rewind())
        return false;
    }

    WebPBitstreamFeatures features;
    VP8StatusCode status = WebPGetFeatures(buffer, WEBP_VP8_HEADER_SIZE, &features);
    if (VP8_STATUS_OK != status) {
        return false; // Invalid WebP file.
    }

    // sanity check for image size that's about to be decoded.
    {
        const int64_t size = sk_64_mul(features.width, features.height);
        if (!sk_64_isS32(size)) {
            return false;
        }
        // now check that if we are 4-bytes per pixel, we also don't overflow
        if (sk_64_asS32(size) > (0x7FFFFFFF >> 2)) {
            return false;
        }
    }

    if (info) {
        // FIXME: Is N32 the right type?
        // Is unpremul the right type? Clients of SkCodec may assume it's the
        // best type, when Skia currently cannot draw unpremul (and raster is faster
        // with premul).
        *info = SkImageInfo::Make(features.width, features.height, kN32_SkColorType,
                                  SkToBool(features.has_alpha) ? kUnpremul_SkAlphaType
                                                              : kOpaque_SkAlphaType);
    }
    return true;
}

SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) {
    SkAutoTDelete<SkStream> streamDeleter(stream);
    SkImageInfo info;
    if (webp_parse_header(stream, &info)) {
        return new SkWebpCodec(info, streamDeleter.detach());
    }
    return nullptr;
}

// This version is slightly different from SkCodecPriv's version of conversion_possible. It
// supports both byte orders for 8888.
static bool webp_conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
    if (dst.profileType() != src.profileType()) {
        return false;
    }

    if (!valid_alpha(dst.alphaType(), src.alphaType())) {
        return false;
    }

    switch (dst.colorType()) {
        // Both byte orders are supported.
        case kBGRA_8888_SkColorType:
        case kRGBA_8888_SkColorType:
            return true;
        case kRGB_565_SkColorType:
            return src.alphaType() == kOpaque_SkAlphaType;
        default:
            return false;
    }
}

SkISize SkWebpCodec::onGetScaledDimensions(float desiredScale) const {
    SkISize dim = this->getInfo().dimensions();
    // SkCodec treats zero dimensional images as errors, so the minimum size
    // that we will recommend is 1x1.
    dim.fWidth = SkTMax(1, SkScalarRoundToInt(desiredScale * dim.fWidth));
    dim.fHeight = SkTMax(1, SkScalarRoundToInt(desiredScale * dim.fHeight));
    return dim;
}

bool SkWebpCodec::onDimensionsSupported(const SkISize& dim) {
    const SkImageInfo& info = this->getInfo();
    return dim.width() >= 1 && dim.width() <= info.width()
            && dim.height() >= 1 && dim.height() <= info.height();
}

static WEBP_CSP_MODE webp_decode_mode(SkColorType ct, bool premultiply) {
    switch (ct) {
        case kBGRA_8888_SkColorType:
            return premultiply ? MODE_bgrA : MODE_BGRA;
        case kRGBA_8888_SkColorType:
            return premultiply ? MODE_rgbA : MODE_RGBA;
        case kRGB_565_SkColorType:
            return MODE_RGB_565;
        default:
            return MODE_LAST;
    }
}

// The WebP decoding API allows us to incrementally pass chunks of bytes as we receive them to the
// decoder with WebPIAppend. In order to do so, we need to read chunks from the SkStream. This size
// is arbitrary.
static const size_t BUFFER_SIZE = 4096;

bool SkWebpCodec::onGetValidSubset(SkIRect* desiredSubset) const {
    if (!desiredSubset) {
        return false;
    }

    SkIRect dimensions  = SkIRect::MakeSize(this->getInfo().dimensions());
    if (!dimensions.contains(*desiredSubset)) {
        return false;
    }

    // As stated below, libwebp snaps to even left and top. Make sure top and left are even, so we
    // decode this exact subset.
    // Leave right and bottom unmodified, so we suggest a slightly larger subset than requested.
    desiredSubset->fLeft = (desiredSubset->fLeft >> 1) << 1;
    desiredSubset->fTop = (desiredSubset->fTop >> 1) << 1;
    return true;
}

SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
                                         const Options& options, SkPMColor*, int*,
                                         int* rowsDecoded) {
    if (!webp_conversion_possible(dstInfo, this->getInfo())) {
        return kInvalidConversion;
    }

    WebPDecoderConfig config;
    if (0 == WebPInitDecoderConfig(&config)) {
        // ABI mismatch.
        // FIXME: New enum for this?
        return kInvalidInput;
    }

    // Free any memory associated with the buffer. Must be called last, so we declare it first.
    SkAutoTCallVProc<WebPDecBuffer, WebPFreeDecBuffer> autoFree(&(config.output));

    SkIRect bounds = SkIRect::MakeSize(this->getInfo().dimensions());
    if (options.fSubset) {
        // Caller is requesting a subset.
        if (!bounds.contains(*options.fSubset)) {
            // The subset is out of bounds.
            return kInvalidParameters;
        }

        bounds = *options.fSubset;

        // This is tricky. libwebp snaps the top and left to even values. We could let libwebp
        // do the snap, and return a subset which is a different one than requested. The problem
        // with that approach is that the caller may try to stitch subsets together, and if we
        // returned different subsets than requested, there would be artifacts at the boundaries.
        // Instead, we report that we cannot support odd values for top and left..
        if (!SkIsAlign2(bounds.fLeft) || !SkIsAlign2(bounds.fTop)) {
            return kInvalidParameters;
        }

#ifdef SK_DEBUG
        {
            // Make a copy, since getValidSubset can change its input.
            SkIRect subset(bounds);
            // That said, getValidSubset should *not* change its input, in this case; otherwise
            // getValidSubset does not match the actual subsets we can do.
            SkASSERT(this->getValidSubset(&subset) && subset == bounds);
        }
#endif

        config.options.use_cropping = 1;
        config.options.crop_left = bounds.fLeft;
        config.options.crop_top = bounds.fTop;
        config.options.crop_width = bounds.width();
        config.options.crop_height = bounds.height();
    }

    SkISize dstDimensions = dstInfo.dimensions();
    if (bounds.size() != dstDimensions) {
        // Caller is requesting scaling.
        config.options.use_scaling = 1;
        config.options.scaled_width = dstDimensions.width();
        config.options.scaled_height = dstDimensions.height();
    }

    config.output.colorspace = webp_decode_mode(dstInfo.colorType(),
            dstInfo.alphaType() == kPremul_SkAlphaType);
    config.output.u.RGBA.rgba = (uint8_t*) dst;
    config.output.u.RGBA.stride = (int) rowBytes;
    config.output.u.RGBA.size = dstInfo.getSafeSize(rowBytes);
    config.output.is_external_memory = 1;

    SkAutoTCallVProc<WebPIDecoder, WebPIDelete> idec(WebPIDecode(nullptr, 0, &config));
    if (!idec) {
        return kInvalidInput;
    }

    SkAutoTMalloc<uint8_t> storage(BUFFER_SIZE);
    uint8_t* buffer = storage.get();
    while (true) {
        const size_t bytesRead = stream()->read(buffer, BUFFER_SIZE);
        if (0 == bytesRead) {
            WebPIDecGetRGB(idec, rowsDecoded, NULL, NULL, NULL);
            return kIncompleteInput;
        }

        switch (WebPIAppend(idec, buffer, bytesRead)) {
            case VP8_STATUS_OK:
                return kSuccess;
            case VP8_STATUS_SUSPENDED:
                // Break out of the switch statement. Continue the loop.
                break;
            default:
                return kInvalidInput;
        }
    }
}

SkWebpCodec::SkWebpCodec(const SkImageInfo& info, SkStream* stream)
    : INHERITED(info, stream) {}
<commit_msg>Fix truncated webp images DO NOT MERGE<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkCodecPriv.h"
#include "SkWebpCodec.h"
#include "SkTemplates.h"

// A WebP decoder on top of (subset of) libwebp
// For more information on WebP image format, and libwebp library, see:
//   https://code.google.com/speed/webp/
//   http://www.webmproject.org/code/#libwebp-webp-image-library
//   https://chromium.googlesource.com/webm/libwebp

// If moving libwebp out of skia source tree, path for webp headers must be
// updated accordingly. Here, we enforce using local copy in webp sub-directory.
#include "webp/decode.h"
#include "webp/encode.h"

bool SkWebpCodec::IsWebp(const void* buf, size_t bytesRead) {
    // WEBP starts with the following:
    // RIFFXXXXWEBPVP
    // Where XXXX is unspecified.
    const char* bytes = static_cast<const char*>(buf);
    return bytesRead >= 14 && !memcmp(bytes, "RIFF", 4) && !memcmp(&bytes[8], "WEBPVP", 6);
}

// Parse headers of RIFF container, and check for valid Webp (VP8) content.
// NOTE: This calls peek instead of read, since onGetPixels will need these
// bytes again.
static bool webp_parse_header(SkStream* stream, SkImageInfo* info) {
    unsigned char buffer[WEBP_VP8_HEADER_SIZE];
    SkASSERT(WEBP_VP8_HEADER_SIZE <= SkCodec::MinBufferedBytesNeeded());

    const size_t bytesPeeked = stream->peek(buffer, WEBP_VP8_HEADER_SIZE);
    if (bytesPeeked != WEBP_VP8_HEADER_SIZE) {
        // Use read + rewind as a backup
        if (stream->read(buffer, WEBP_VP8_HEADER_SIZE) != WEBP_VP8_HEADER_SIZE
            || !stream->rewind())
        return false;
    }

    WebPBitstreamFeatures features;
    VP8StatusCode status = WebPGetFeatures(buffer, WEBP_VP8_HEADER_SIZE, &features);
    if (VP8_STATUS_OK != status) {
        return false; // Invalid WebP file.
    }

    // sanity check for image size that's about to be decoded.
    {
        const int64_t size = sk_64_mul(features.width, features.height);
        if (!sk_64_isS32(size)) {
            return false;
        }
        // now check that if we are 4-bytes per pixel, we also don't overflow
        if (sk_64_asS32(size) > (0x7FFFFFFF >> 2)) {
            return false;
        }
    }

    if (info) {
        // FIXME: Is N32 the right type?
        // Is unpremul the right type? Clients of SkCodec may assume it's the
        // best type, when Skia currently cannot draw unpremul (and raster is faster
        // with premul).
        *info = SkImageInfo::Make(features.width, features.height, kN32_SkColorType,
                                  SkToBool(features.has_alpha) ? kUnpremul_SkAlphaType
                                                              : kOpaque_SkAlphaType);
    }
    return true;
}

SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) {
    SkAutoTDelete<SkStream> streamDeleter(stream);
    SkImageInfo info;
    if (webp_parse_header(stream, &info)) {
        return new SkWebpCodec(info, streamDeleter.detach());
    }
    return nullptr;
}

// This version is slightly different from SkCodecPriv's version of conversion_possible. It
// supports both byte orders for 8888.
static bool webp_conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
    if (dst.profileType() != src.profileType()) {
        return false;
    }

    if (!valid_alpha(dst.alphaType(), src.alphaType())) {
        return false;
    }

    switch (dst.colorType()) {
        // Both byte orders are supported.
        case kBGRA_8888_SkColorType:
        case kRGBA_8888_SkColorType:
            return true;
        case kRGB_565_SkColorType:
            return src.alphaType() == kOpaque_SkAlphaType;
        default:
            return false;
    }
}

SkISize SkWebpCodec::onGetScaledDimensions(float desiredScale) const {
    SkISize dim = this->getInfo().dimensions();
    // SkCodec treats zero dimensional images as errors, so the minimum size
    // that we will recommend is 1x1.
    dim.fWidth = SkTMax(1, SkScalarRoundToInt(desiredScale * dim.fWidth));
    dim.fHeight = SkTMax(1, SkScalarRoundToInt(desiredScale * dim.fHeight));
    return dim;
}

bool SkWebpCodec::onDimensionsSupported(const SkISize& dim) {
    const SkImageInfo& info = this->getInfo();
    return dim.width() >= 1 && dim.width() <= info.width()
            && dim.height() >= 1 && dim.height() <= info.height();
}

static WEBP_CSP_MODE webp_decode_mode(SkColorType ct, bool premultiply) {
    switch (ct) {
        case kBGRA_8888_SkColorType:
            return premultiply ? MODE_bgrA : MODE_BGRA;
        case kRGBA_8888_SkColorType:
            return premultiply ? MODE_rgbA : MODE_RGBA;
        case kRGB_565_SkColorType:
            return MODE_RGB_565;
        default:
            return MODE_LAST;
    }
}

// The WebP decoding API allows us to incrementally pass chunks of bytes as we receive them to the
// decoder with WebPIAppend. In order to do so, we need to read chunks from the SkStream. This size
// is arbitrary.
static const size_t BUFFER_SIZE = 4096;

bool SkWebpCodec::onGetValidSubset(SkIRect* desiredSubset) const {
    if (!desiredSubset) {
        return false;
    }

    SkIRect dimensions  = SkIRect::MakeSize(this->getInfo().dimensions());
    if (!dimensions.contains(*desiredSubset)) {
        return false;
    }

    // As stated below, libwebp snaps to even left and top. Make sure top and left are even, so we
    // decode this exact subset.
    // Leave right and bottom unmodified, so we suggest a slightly larger subset than requested.
    desiredSubset->fLeft = (desiredSubset->fLeft >> 1) << 1;
    desiredSubset->fTop = (desiredSubset->fTop >> 1) << 1;
    return true;
}

SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
                                         const Options& options, SkPMColor*, int*,
                                         int* rowsDecoded) {
    if (!webp_conversion_possible(dstInfo, this->getInfo())) {
        return kInvalidConversion;
    }

    WebPDecoderConfig config;
    if (0 == WebPInitDecoderConfig(&config)) {
        // ABI mismatch.
        // FIXME: New enum for this?
        return kInvalidInput;
    }

    // Free any memory associated with the buffer. Must be called last, so we declare it first.
    SkAutoTCallVProc<WebPDecBuffer, WebPFreeDecBuffer> autoFree(&(config.output));

    SkIRect bounds = SkIRect::MakeSize(this->getInfo().dimensions());
    if (options.fSubset) {
        // Caller is requesting a subset.
        if (!bounds.contains(*options.fSubset)) {
            // The subset is out of bounds.
            return kInvalidParameters;
        }

        bounds = *options.fSubset;

        // This is tricky. libwebp snaps the top and left to even values. We could let libwebp
        // do the snap, and return a subset which is a different one than requested. The problem
        // with that approach is that the caller may try to stitch subsets together, and if we
        // returned different subsets than requested, there would be artifacts at the boundaries.
        // Instead, we report that we cannot support odd values for top and left..
        if (!SkIsAlign2(bounds.fLeft) || !SkIsAlign2(bounds.fTop)) {
            return kInvalidParameters;
        }

#ifdef SK_DEBUG
        {
            // Make a copy, since getValidSubset can change its input.
            SkIRect subset(bounds);
            // That said, getValidSubset should *not* change its input, in this case; otherwise
            // getValidSubset does not match the actual subsets we can do.
            SkASSERT(this->getValidSubset(&subset) && subset == bounds);
        }
#endif

        config.options.use_cropping = 1;
        config.options.crop_left = bounds.fLeft;
        config.options.crop_top = bounds.fTop;
        config.options.crop_width = bounds.width();
        config.options.crop_height = bounds.height();
    }

    SkISize dstDimensions = dstInfo.dimensions();
    if (bounds.size() != dstDimensions) {
        // Caller is requesting scaling.
        config.options.use_scaling = 1;
        config.options.scaled_width = dstDimensions.width();
        config.options.scaled_height = dstDimensions.height();
    }

    config.output.colorspace = webp_decode_mode(dstInfo.colorType(),
            dstInfo.alphaType() == kPremul_SkAlphaType);
    config.output.u.RGBA.rgba = (uint8_t*) dst;
    config.output.u.RGBA.stride = (int) rowBytes;
    config.output.u.RGBA.size = dstInfo.getSafeSize(rowBytes);
    config.output.is_external_memory = 1;

    SkAutoTCallVProc<WebPIDecoder, WebPIDelete> idec(WebPIDecode(nullptr, 0, &config));
    if (!idec) {
        return kInvalidInput;
    }

    SkAutoTMalloc<uint8_t> storage(BUFFER_SIZE);
    uint8_t* buffer = storage.get();
    while (true) {
        const size_t bytesRead = stream()->read(buffer, BUFFER_SIZE);
        if (0 == bytesRead) {
            if (!WebPIDecGetRGB(idec, rowsDecoded, NULL, NULL, NULL)
                    || rowsDecoded && *rowsDecoded <= 0) {
                return kInvalidInput;
            }
            return kIncompleteInput;
        }

        switch (WebPIAppend(idec, buffer, bytesRead)) {
            case VP8_STATUS_OK:
                return kSuccess;
            case VP8_STATUS_SUSPENDED:
                // Break out of the switch statement. Continue the loop.
                break;
            default:
                return kInvalidInput;
        }
    }
}

SkWebpCodec::SkWebpCodec(const SkImageInfo& info, SkStream* stream)
    : INHERITED(info, stream) {}
<|endoftext|>


<commit_before>// Copyright 2017 Global Phasing Ltd.

#include "gemmi/symmetry.hpp"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>

namespace py = pybind11;
using namespace gemmi;

PYBIND11_MAKE_OPAQUE(std::vector<Op::Tran>)

void add_symmetry(py::module& m) {
  py::bind_vector<std::vector<Op::Tran>>(m, "TranList");
  py::class_<Op>(m, "Op")
    .def(py::init<>(&Op::identity))
    .def(py::init(&parse_triplet))
    .def_property_readonly_static("TDEN",
            [](py::object) -> int { return Op::TDEN; },
            "Denominator (integer) for the translation vector.")
    .def_readwrite("rot", &Op::rot, "3x3 integer matrix.")
    .def_readwrite("tran", &Op::tran,
       "Numerators (integers) of the translation vector. Denominator TDEN=24.")
    .def("triplet", &Op::triplet, "Returns coordinate triplet x,y,z.")
    .def("det_rot", &Op::det_rot, "Determinant of the 3x3 matrix.")
    .def("inverse", [](const Op& self) { return self.inverse(); },
         "Returns inverted operator.")
    .def("negated", &Op::negated, "Returns Op with all elements nagated")
    .def("translated", &Op::translated, py::arg("a"), "Adds a to tran")
    .def("wrap", &Op::wrap, "Wrap the translation part to [0,1)")
    .def("combine", &Op::combine, py::arg("b"),
         "Combine two symmetry operations.")
    .def("seitz", [](const Op& self) {
            auto arr = self.seitz();
            auto mat = py::list();
            py::object fr = py::module::import("fractions").attr("Fraction");
            for (int i = 0; i < 4; ++i) {
              auto row = py::list();
              for (int j = 0; j < 4; ++j) {
                auto v = arr[i][j];
                if (j == 3 && i != 3 && v != 0)
                  row.append(fr(v, Op::TDEN));
                else
                  row.append(v);
              }
              mat.append(row);
            }
            return mat;
         }, "Returns Seitz matrix (integers and fractions)")
    .def("float_seitz", &Op::float_seitz, "Returns Seitz matrix (floats)")
    .def("apply_to_hkl", &Op::apply_to_hkl, py::arg("hkl"))
    .def("phase_shift", &Op::phase_shift,
         py::arg("h"), py::arg("k"), py::arg("l"))
    .def("__mul__", [](const Op &a, const Op &b) { return a * b; },
         py::is_operator())
    .def("__mul__", [](const Op &a, const std::string &b) {
            return a * parse_triplet(b);
         }, py::is_operator())
    .def("__rmul__", [](const Op &a, const std::string &b) {
            return parse_triplet(b) * a;
         }, py::is_operator())
    .def("__eq__", [](const Op &a, const Op &b) { return a == b; },
         py::is_operator())
    .def("__eq__", [](const Op &a, const std::string& b) {
            return a == parse_triplet(b);
         }, py::is_operator())
#if PY_MAJOR_VERSION < 3  // in Py3 != is inferred from ==
    .def("__ne__", [](const Op &a, const Op &b) { return a != b; },
         py::is_operator())
    .def("__ne__", [](const Op &a, const std::string& b) {
            return a != parse_triplet(b);
         }, py::is_operator())
#endif
    .def("__hash__", [](const Op &self) { return std::hash<Op>()(self); })
    .def("__repr__", [](const Op &self) {
        return "<gemmi.Op(\"" + self.triplet() + "\")>";
    });

  py::class_<FractOp>(m, "FractOp")
    .def(py::init<>())
    .def(py::init<const Op&>())
    .def_readwrite("op", &FractOp::op)
    .def("triplet", &FractOp::triplet)
    .def("inverse", &FractOp::inverse)
    .def("__mul__", [](const FractOp &a, const FractOp &b) { return a * b; },
         py::is_operator())
    .def("__eq__", [](const FractOp &a, const FractOp &b) { return a == b; },
         py::is_operator())
#if PY_MAJOR_VERSION < 3  // in Py3 != is inferred from ==
    .def("__ne__", [](const FractOp &a, const FractOp &b) { return a != b; },
         py::is_operator())
#endif
    .def("__repr__", [](const FractOp& self) {
        return "<gemmi.FractOp " + self.triplet() + ">";
    });

  m.def("parse_triplet", &parse_triplet, py::arg("triplet"),
        "Parse coordinate triplet into gemmi.Op.");
  m.def("parse_triplet_part", &parse_triplet_part, py::arg("s"),
        "Parse one of the three parts of a triplet.");
  m.def("make_triplet_part", &make_triplet_part,
        py::arg("x"), py::arg("y"), py::arg("z"), py::arg("w"),
        py::arg("is_fract")=false, py::arg("style")='x',
        "Make one of the three parts of a triplet.");

  py::class_<GroupOps>(m, "GroupOps")
    .def(py::init<>())
    .def("__iter__", [](const GroupOps& self) {
        return py::make_iterator(self);
    }, py::keep_alive<0, 1>())
    .def("__eq__", [](const GroupOps &a, const GroupOps &b) {
            return a.is_same_as(b);
    }, py::is_operator())
#if PY_MAJOR_VERSION < 3  // in Py3 != is inferred from ==
    .def("__ne__", [](const GroupOps &a, const GroupOps &b) {
            return !a.is_same_as(b);
    }, py::is_operator())
#endif
    .def("__len__", [](const GroupOps& g) { return g.order(); })
    .def_readwrite("sym_ops", &GroupOps::sym_ops,
               "Symmetry operations (to be combined with centering vectors).")
    .def_readwrite("cen_ops", &GroupOps::cen_ops, "Centering vectors.")
    .def("is_centric", &GroupOps::is_centric)
    .def("find_grid_factors", &GroupOps::find_grid_factors,
         "Minimal multiplicity for real-space grid (e.g. 1,1,6 for P61).")
    .def("change_basis", &GroupOps::change_basis, py::arg("cob"),
         "Applies the change-of-basis operator (in place).");

  py::class_<SpaceGroup>(m, "SpaceGroup")
    .def(py::init<>())
    .def(py::init([](int n) {
           return const_cast<SpaceGroup&>(get_spacegroup_by_number(n));
         }), py::arg("ccp4"), py::return_value_policy::reference)
    .def(py::init([](const std::string& s) {
           return const_cast<SpaceGroup&>(get_spacegroup_by_name(s));
         }), py::arg("hm"), py::return_value_policy::reference)
    //.def(py::init(&find_spacegroup_by_name))
    .def("__repr__", [](const SpaceGroup &self) {
        return "<gemmi.SpaceGroup(\"" + self.xhm() + "\")>";
    })
    .def_readonly("number", &SpaceGroup::number, "number 1-230.")
    .def_readonly("ccp4", &SpaceGroup::ccp4, "ccp4 number")
    // Intel Compiler would not compile .def_readonly("hm", ...),
    // the difference with hm, qualifier and hall is that they are char[N]
    .def_property_readonly("hm", [](const SpaceGroup &self) -> const char* {
        return self.hm;
    }, "Hermann-Mauguin name")
    .def_readonly("ext", &SpaceGroup::ext, "Extension (1, 2, H, R or none)")
    .def_property_readonly("qualifier", [](const SpaceGroup &s) -> const char* {
        return s.qualifier;
    }, "e.g. 'cab'")
    .def_property_readonly("hall", [](const SpaceGroup &self) -> const char* {
        return self.hall;
    }, "Hall symbol")
    .def("xhm", &SpaceGroup::xhm, "extended Hermann-Mauguin name")
    .def("short_name", &SpaceGroup::short_name,
         "H-M name w/o spaces and with 1's removed in '1 ... 1'.")
    .def("point_group_hm", &SpaceGroup::point_group_hm,
         "Returns H-M name of the point group.")
    .def("laue_str", &SpaceGroup::laue_str,
         "Returns name of the Laue class (for centrosymmetric groups "
         "the same as point_group_hm).")
    .def("crystal_system_str", &SpaceGroup::crystal_system_str,
         "Returns lower-case name of the crystal system.")
    .def("is_reference_setting", &SpaceGroup::is_reference_setting)
    .def("operations", &SpaceGroup::operations, "Group of operations");

  m.def("spacegroup_table", []() {
            return py::make_iterator(spacegroup_tables::main);
        }, py::return_value_policy::reference);
  m.def("generators_from_hall", &generators_from_hall, py::arg("hall"),
        "Parse Hall notation.");
  m.def("symops_from_hall", &symops_from_hall, py::arg("hall"),
        "Parse Hall notation.");
  m.def("find_spacegroup_by_number", &find_spacegroup_by_number,
        py::arg("ccp4"), py::return_value_policy::reference,
        "Returns space-group of given number.");
  m.def("find_spacegroup_by_name", &find_spacegroup_by_name, py::arg("hm"),
        py::return_value_policy::reference,
        "Returns space-group with given name.");
  m.def("get_spacegroup_reference_setting", &get_spacegroup_reference_setting,
        py::arg("number"), py::return_value_policy::reference);
  m.def("find_spacegroup_by_ops", &find_spacegroup_by_ops,
        py::arg("group_ops"), py::return_value_policy::reference,
        "Returns space-group with identical operations.");
}
<commit_msg>fix dynamic linker error<commit_after>// Copyright 2017 Global Phasing Ltd.

#include "gemmi/symmetry.hpp"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>

namespace py = pybind11;
using namespace gemmi;

PYBIND11_MAKE_OPAQUE(std::vector<Op::Tran>)

void add_symmetry(py::module& m) {
  py::bind_vector<std::vector<Op::Tran>>(m, "TranList");
  py::class_<Op>(m, "Op")
    .def(py::init<>(&Op::identity))
    .def(py::init(&parse_triplet))
    .def_property_readonly_static("TDEN", [](py::object) { return Op::TDEN; },
                           "Denominator (integer) for the translation vector.")
    .def_readwrite("rot", &Op::rot, "3x3 integer matrix.")
    .def_readwrite("tran", &Op::tran,
       "Numerators (integers) of the translation vector. Denominator TDEN=24.")
    .def("triplet", &Op::triplet, "Returns coordinate triplet x,y,z.")
    .def("det_rot", &Op::det_rot, "Determinant of the 3x3 matrix.")
    .def("inverse", [](const Op& self) { return self.inverse(); },
         "Returns inverted operator.")
    .def("negated", &Op::negated, "Returns Op with all elements nagated")
    .def("translated", &Op::translated, py::arg("a"), "Adds a to tran")
    .def("wrap", &Op::wrap, "Wrap the translation part to [0,1)")
    .def("combine", &Op::combine, py::arg("b"),
         "Combine two symmetry operations.")
    .def("seitz", [](const Op& self) {
            auto arr = self.seitz();
            auto mat = py::list();
            py::object fr = py::module::import("fractions").attr("Fraction");
            for (int i = 0; i < 4; ++i) {
              auto row = py::list();
              for (int j = 0; j < 4; ++j) {
                auto v = arr[i][j];
                if (j == 3 && i != 3 && v != 0)
                  row.append(fr(v, Op::TDEN + 0));  // +0 to avoid linker error
                else
                  row.append(v);
              }
              mat.append(row);
            }
            return mat;
         }, "Returns Seitz matrix (integers and fractions)")
    .def("float_seitz", &Op::float_seitz, "Returns Seitz matrix (floats)")
    .def("apply_to_hkl", &Op::apply_to_hkl, py::arg("hkl"))
    .def("phase_shift", &Op::phase_shift,
         py::arg("h"), py::arg("k"), py::arg("l"))
    .def("__mul__", [](const Op &a, const Op &b) { return a * b; },
         py::is_operator())
    .def("__mul__", [](const Op &a, const std::string &b) {
            return a * parse_triplet(b);
         }, py::is_operator())
    .def("__rmul__", [](const Op &a, const std::string &b) {
            return parse_triplet(b) * a;
         }, py::is_operator())
    .def("__eq__", [](const Op &a, const Op &b) { return a == b; },
         py::is_operator())
    .def("__eq__", [](const Op &a, const std::string& b) {
            return a == parse_triplet(b);
         }, py::is_operator())
#if PY_MAJOR_VERSION < 3  // in Py3 != is inferred from ==
    .def("__ne__", [](const Op &a, const Op &b) { return a != b; },
         py::is_operator())
    .def("__ne__", [](const Op &a, const std::string& b) {
            return a != parse_triplet(b);
         }, py::is_operator())
#endif
    .def("__hash__", [](const Op &self) { return std::hash<Op>()(self); })
    .def("__repr__", [](const Op &self) {
        return "<gemmi.Op(\"" + self.triplet() + "\")>";
    });

  py::class_<FractOp>(m, "FractOp")
    .def(py::init<>())
    .def(py::init<const Op&>())
    .def_readwrite("op", &FractOp::op)
    .def("triplet", &FractOp::triplet)
    .def("inverse", &FractOp::inverse)
    .def("__mul__", [](const FractOp &a, const FractOp &b) { return a * b; },
         py::is_operator())
    .def("__eq__", [](const FractOp &a, const FractOp &b) { return a == b; },
         py::is_operator())
#if PY_MAJOR_VERSION < 3  // in Py3 != is inferred from ==
    .def("__ne__", [](const FractOp &a, const FractOp &b) { return a != b; },
         py::is_operator())
#endif
    .def("__repr__", [](const FractOp& self) {
        return "<gemmi.FractOp " + self.triplet() + ">";
    });

  m.def("parse_triplet", &parse_triplet, py::arg("triplet"),
        "Parse coordinate triplet into gemmi.Op.");
  m.def("parse_triplet_part", &parse_triplet_part, py::arg("s"),
        "Parse one of the three parts of a triplet.");
  m.def("make_triplet_part", &make_triplet_part,
        py::arg("x"), py::arg("y"), py::arg("z"), py::arg("w"),
        py::arg("is_fract")=false, py::arg("style")='x',
        "Make one of the three parts of a triplet.");

  py::class_<GroupOps>(m, "GroupOps")
    .def(py::init<>())
    .def("__iter__", [](const GroupOps& self) {
        return py::make_iterator(self);
    }, py::keep_alive<0, 1>())
    .def("__eq__", [](const GroupOps &a, const GroupOps &b) {
            return a.is_same_as(b);
    }, py::is_operator())
#if PY_MAJOR_VERSION < 3  // in Py3 != is inferred from ==
    .def("__ne__", [](const GroupOps &a, const GroupOps &b) {
            return !a.is_same_as(b);
    }, py::is_operator())
#endif
    .def("__len__", [](const GroupOps& g) { return g.order(); })
    .def_readwrite("sym_ops", &GroupOps::sym_ops,
               "Symmetry operations (to be combined with centering vectors).")
    .def_readwrite("cen_ops", &GroupOps::cen_ops, "Centering vectors.")
    .def("is_centric", &GroupOps::is_centric)
    .def("find_grid_factors", &GroupOps::find_grid_factors,
         "Minimal multiplicity for real-space grid (e.g. 1,1,6 for P61).")
    .def("change_basis", &GroupOps::change_basis, py::arg("cob"),
         "Applies the change-of-basis operator (in place).");

  py::class_<SpaceGroup>(m, "SpaceGroup")
    .def(py::init<>())
    .def(py::init([](int n) {
           return const_cast<SpaceGroup&>(get_spacegroup_by_number(n));
         }), py::arg("ccp4"), py::return_value_policy::reference)
    .def(py::init([](const std::string& s) {
           return const_cast<SpaceGroup&>(get_spacegroup_by_name(s));
         }), py::arg("hm"), py::return_value_policy::reference)
    //.def(py::init(&find_spacegroup_by_name))
    .def("__repr__", [](const SpaceGroup &self) {
        return "<gemmi.SpaceGroup(\"" + self.xhm() + "\")>";
    })
    .def_readonly("number", &SpaceGroup::number, "number 1-230.")
    .def_readonly("ccp4", &SpaceGroup::ccp4, "ccp4 number")
    // Intel Compiler would not compile .def_readonly("hm", ...),
    // the difference with hm, qualifier and hall is that they are char[N]
    .def_property_readonly("hm", [](const SpaceGroup &self) -> const char* {
        return self.hm;
    }, "Hermann-Mauguin name")
    .def_readonly("ext", &SpaceGroup::ext, "Extension (1, 2, H, R or none)")
    .def_property_readonly("qualifier", [](const SpaceGroup &s) -> const char* {
        return s.qualifier;
    }, "e.g. 'cab'")
    .def_property_readonly("hall", [](const SpaceGroup &self) -> const char* {
        return self.hall;
    }, "Hall symbol")
    .def("xhm", &SpaceGroup::xhm, "extended Hermann-Mauguin name")
    .def("short_name", &SpaceGroup::short_name,
         "H-M name w/o spaces and with 1's removed in '1 ... 1'.")
    .def("point_group_hm", &SpaceGroup::point_group_hm,
         "Returns H-M name of the point group.")
    .def("laue_str", &SpaceGroup::laue_str,
         "Returns name of the Laue class (for centrosymmetric groups "
         "the same as point_group_hm).")
    .def("crystal_system_str", &SpaceGroup::crystal_system_str,
         "Returns lower-case name of the crystal system.")
    .def("is_reference_setting", &SpaceGroup::is_reference_setting)
    .def("operations", &SpaceGroup::operations, "Group of operations");

  m.def("spacegroup_table", []() {
            return py::make_iterator(spacegroup_tables::main);
        }, py::return_value_policy::reference);
  m.def("generators_from_hall", &generators_from_hall, py::arg("hall"),
        "Parse Hall notation.");
  m.def("symops_from_hall", &symops_from_hall, py::arg("hall"),
        "Parse Hall notation.");
  m.def("find_spacegroup_by_number", &find_spacegroup_by_number,
        py::arg("ccp4"), py::return_value_policy::reference,
        "Returns space-group of given number.");
  m.def("find_spacegroup_by_name", &find_spacegroup_by_name, py::arg("hm"),
        py::return_value_policy::reference,
        "Returns space-group with given name.");
  m.def("get_spacegroup_reference_setting", &get_spacegroup_reference_setting,
        py::arg("number"), py::return_value_policy::reference);
  m.def("find_spacegroup_by_ops", &find_spacegroup_by_ops,
        py::arg("group_ops"), py::return_value_policy::reference,
        "Returns space-group with identical operations.");
}
<|endoftext|>


<commit_before>#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
#include <QDateTime>
#include <QByteArray>
#include <iostream>
#include <fstream>
#include <string.h>

#include "testutil.h"

#include "wait.h"
#include "retry.h"

#include "commonutil.h"
#include "jsonutil.h"

using namespace std;

QString getLinkRealname(const QString& softlink);

void test_qprocess()
{
//#define TEST_COMMAND    "du -chs /home/rasmus/gcode/snippet/"
#define TEST_COMMAND    "ls no.such.file.existed.32424"

    QProcess process;
    process.start(TEST_COMMAND);
    process.waitForFinished(-1); // will wait forever until finished

    QString stdout = process.readAllStandardOutput();
    QString stderr = process.readAllStandardError();

    qDebug() << "stdout:" << stdout;
    qDebug() << "stderr:" << stderr;
    qDebug() << "return code:" << process.exitCode();
}

void gen_seed()
{
    qint64 current = QDateTime::currentMSecsSinceEpoch();
    qsrand((uint)(current % 0xffffffff));
}

void test_array()
{
//#define DEFAULT_VIDEO_SOFTLINK  "/var/run/front.videomgr"
#define DEFAULT_VIDEO_SOFTLINK  "/home/rasmus/我的連結"
    getLinkRealname(DEFAULT_VIDEO_SOFTLINK);
}

void test_md5list(int count)
{
    for (int i = 0; i < count; i++) {
        QString md = get_md5sum(get_one_string(i));
        //qDebug() << QString("%1 => %2").arg(str).arg(md);
        if ( md == CIPHER_HASH ) {
            qWarning() << "parameter matched !!";
        }
    }
}

void test_fromconfig()
{
    try {
        std::ifstream infile(gVars.sConfig.toUtf8().data());
        nlohmann::json j;
        infile >> j;

        qDebug() << "parsed!";

        // iterate the array
        for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) {
            //std::cout << it.key() << ":" << it.value() << std::endl;
            for (auto& e: j[it.key()]) {
                std::string key = it.key();
                getHash(key.c_str(), e.get<std::string>().c_str());
            }
        }

    } catch (nlohmann::json::parse_error& e) {
        // output exception information
        std::cout << "message: " << e.what() << '\n'
                  << "exception id: " << e.id << '\n'
                  << "byte position of error: " << e.byte << std::endl;
    }

}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    handleOpt(argc, argv);
    switch (gVars.kTest) {
        case TC_MD5LISTTEST:
            test_md5list(gVars.iCount);
            return 0;
        case TC_ARRAYTEST:
            test_array();
            return 0;
        case TC_MD5SUMTEST:
            get_md5sum(gVars.sTeststring);
            return 0;
        case TC_SHA1SUMTEST:
            get_sha1sum(gVars.sTeststring);
            return 0;
        case TC_HMACTEST:
            test_sha1hmac();
            return 0;
        case TC_READCONFIG:
            test_fromconfig();
            return 0;
        case TC_PROCESS:
            test_qprocess();
            return 0;
        default:
            test_md5list(1);
            return 0;
    }

    WaitOneSecond t1("t1", 2000), t2("t2", 4000);
    WaitOneSecond w("wait", 8000);
    RetryThread foobar;

    // after thread WaitOneSecond finised, it also quit this app
    QObject::connect(&t1, SIGNAL(finished()), &t2, SLOT(start()));
    QObject::connect(&t2, SIGNAL(finished()), &foobar, SLOT(sltNotifyStop()));
    QObject::connect(&w, SIGNAL(finished()), &foobar, SLOT(sltNotifyStop()));
    QObject::connect(&w, SIGNAL(finished()), &app, SLOT(quit()));

    w.start();
    t1.start();
    foobar.start();

    return app.exec();
}
<commit_msg>update qtcmd, print current epoch in msec<commit_after>#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
#include <QDateTime>
#include <QByteArray>
#include <iostream>
#include <fstream>
#include <string.h>

#include "testutil.h"

#include "wait.h"
#include "retry.h"

#include "commonutil.h"
#include "jsonutil.h"

using namespace std;

QString getLinkRealname(const QString& softlink);

void test_qprocess()
{
//#define TEST_COMMAND    "du -chs /home/rasmus/gcode/snippet/"
#define TEST_COMMAND    "ls no.such.file.existed.32424"

    QProcess process;
    process.start(TEST_COMMAND);
    process.waitForFinished(-1); // will wait forever until finished

    QString stdout = process.readAllStandardOutput();
    QString stderr = process.readAllStandardError();

    qDebug() << "stdout:" << stdout;
    qDebug() << "stderr:" << stderr;
    qDebug() << "return code:" << process.exitCode();
}

void gen_seed()
{
    qint64 current = QDateTime::currentMSecsSinceEpoch();
    qsrand((uint)(current % 0xffffffff));
}

void print_current_msec_epoch()
{
    qDebug() << "epoch in msec:" << QDateTime::currentMSecsSinceEpoch();
}

void test_array()
{
//#define DEFAULT_VIDEO_SOFTLINK  "/var/run/front.videomgr"
#define DEFAULT_VIDEO_SOFTLINK  "/home/rasmus/我的連結"
    getLinkRealname(DEFAULT_VIDEO_SOFTLINK);
}

void test_md5list(int count)
{
    for (int i = 0; i < count; i++) {
        QString md = get_md5sum(get_one_string(i));
        //qDebug() << QString("%1 => %2").arg(str).arg(md);
        if ( md == CIPHER_HASH ) {
            qWarning() << "parameter matched !!";
        }
    }
}

void test_fromconfig()
{
    try {
        std::ifstream infile(gVars.sConfig.toUtf8().data());
        nlohmann::json j;
        infile >> j;

        qDebug() << "parsed!";

        // iterate the array
        for (nlohmann::json::iterator it = j.begin(); it != j.end(); ++it) {
            //std::cout << it.key() << ":" << it.value() << std::endl;
            for (auto& e: j[it.key()]) {
                std::string key = it.key();
                getHash(key.c_str(), e.get<std::string>().c_str());
            }
        }

    } catch (nlohmann::json::parse_error& e) {
        // output exception information
        std::cout << "message: " << e.what() << '\n'
                  << "exception id: " << e.id << '\n'
                  << "byte position of error: " << e.byte << std::endl;
    }

}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    print_current_msec_epoch();

    handleOpt(argc, argv);
    switch (gVars.kTest) {
        case TC_MD5LISTTEST:
            test_md5list(gVars.iCount);
            return 0;
        case TC_ARRAYTEST:
            test_array();
            return 0;
        case TC_MD5SUMTEST:
            get_md5sum(gVars.sTeststring);
            return 0;
        case TC_SHA1SUMTEST:
            get_sha1sum(gVars.sTeststring);
            return 0;
        case TC_HMACTEST:
            test_sha1hmac();
            return 0;
        case TC_READCONFIG:
            test_fromconfig();
            return 0;
        case TC_PROCESS:
            test_qprocess();
            return 0;
        default:
            test_md5list(1);
            return 0;
    }

    WaitOneSecond t1("t1", 2000), t2("t2", 4000);
    WaitOneSecond w("wait", 8000);
    RetryThread foobar;

    // after thread WaitOneSecond finised, it also quit this app
    QObject::connect(&t1, SIGNAL(finished()), &t2, SLOT(start()));
    QObject::connect(&t2, SIGNAL(finished()), &foobar, SLOT(sltNotifyStop()));
    QObject::connect(&w, SIGNAL(finished()), &foobar, SLOT(sltNotifyStop()));
    QObject::connect(&w, SIGNAL(finished()), &app, SLOT(quit()));

    w.start();
    t1.start();
    foobar.start();

    return app.exec();
}
<|endoftext|>


<commit_before>
#include <QIcon>
#include <QXmlStreamReader>
#include <QtDebug>
#include <QFileInfo>
#include <QDir>
#include <QMessageBox>

#include "qxmlplaylisthandler.hpp"
#include "qplaylistmodel.hpp"
#include <QMimeData>

QString QPlaylistModel::PRESET_MIME_TYPE("text/x-projectM-preset");

class XmlReadFunctor {
	public:
		XmlReadFunctor(QPlaylistModel & model) : m_model(model) {}

		inline void setPlaylistDesc(const QString & desc) {
			m_model.setPlaylistDesc(desc);
		}

		inline void appendItem(const QString & url, const QString & name, int rating) {
			m_model.appendRow(url, name, rating);
		}

	private:
		QPlaylistModel & m_model;

};

class XmlWriteFunctor {
	public:
		XmlWriteFunctor(QPlaylistModel & model) : m_model(model), m_index(0) {}

		inline const QString & playlistDesc() const {
			return m_model.playlistDesc();
		}

		inline bool nextItem(QString & url, int & rating) {

			if (m_index >= m_model.rowCount())
				return false;

			QModelIndex modelIndex = m_model.index(m_index, 0);
			url = m_model.data(modelIndex, QPlaylistModel::URLInfoRole).toString();
			rating = m_model.data(modelIndex, QPlaylistModel::RatingRole).toInt();
			m_index++;
			return true;
		}
	private:
		QPlaylistModel & m_model;
		int m_index;

};

QPlaylistModel::QPlaylistModel ( projectM & _projectM, QObject * parent ) :
		QAbstractTableModel ( parent ), m_projectM ( _projectM )
{

}

void QPlaylistModel::updateItemHighlights()
{
	if ( rowCount() == 0 )
		return;

	emit ( dataChanged ( this->index ( 0,0 ), this->index ( rowCount()-1,columnCount()-1 ) ) );
}

bool QPlaylistModel::setData ( const QModelIndex & index, const QVariant & value, int role )
{
	if ( role == QPlaylistModel::RatingRole )
	{
		m_projectM.changePresetRating(index.row(), value.toInt());
		emit ( dataChanged ( index, index ) );
		return true;
	}
	else
		return QAbstractTableModel::setData ( index, value, role );

}

Qt::ItemFlags QPlaylistModel::flags(const QModelIndex &index) const
{
	Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);

	if (index.isValid())
		return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
	else
		return Qt::ItemIsDropEnabled | defaultFlags;
}

 bool QPlaylistModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
				int row, int column, const QModelIndex &parent)
{
	qDebug() << "DROP";

	if (!data->hasFormat(PRESET_MIME_TYPE))
		return false;

	if (action == Qt::IgnoreAction)
		return true;

	if (column > 0)
		return false;

	return true;
}

QVariant QPlaylistModel::ratingToIcon ( int rating )  const
{
	switch ( rating )
	{
		case 1:
			return QVariant ( QIcon ( ":/images/icons/face0.png" ) );
		case 2:
			return QVariant ( QIcon ( ":/images/icons/face1.png" ) );
		case 3:
			return QVariant ( QIcon ( ":/images/icons/face2.png" ) );
		case 4:
			return QVariant ( QIcon ( ":/images/icons/face3.png" ) );
		case 5:
			return QVariant ( QIcon ( ":/images/icons/face4.png" ) );
		case 6:
			return QVariant ( QIcon ( ":/images/icons/face5.png" ) );
		default:
			if (rating < 0)
				return QVariant ( QIcon ( ":/images/icons/face0.png" ) );
			else
				return QVariant ( QIcon ( ":/images/icons/face5.png" ) );
	}
}

QString QPlaylistModel::getSillyRatingToolTip(int rating) {

switch (rating) {
	case 1:
		return QString("Rather watch grass grow than watch this");
	case 2:
		return QString("A very poor preset");
	case 3:
		return QString("Tolerable");
	case 4:
		return QString("Pretty good");
	case 5:
		return QString("Trippy eye candy");
	case 6:
		return QString("Crafted by a psychotic deity");
	default:
		if (rating <= 0 )
			return QString("So bad it literally makes other presets bad!");
		else
			return QString("Better than projectM itself!");
}
}

QVariant QPlaylistModel::data ( const QModelIndex & index, int role = Qt::DisplayRole ) const
{

	if (!index.isValid())
		return QVariant();

	unsigned int pos;

	switch ( role )
	{
		case Qt::DisplayRole:
			if ( index.column() == 0 )
				return QVariant ( QString ( m_projectM.getPresetName ( index.row() ).c_str() ) );
			else
				return ratingToIcon ( m_projectM.getPresetRating(index.row()) );
		case Qt::ToolTipRole:
			if ( index.column() == 0 )
				return QVariant ( QString ( m_projectM.getPresetName ( index.row() ).c_str() ) );
			else
				return QString ( getSillyRatingToolTip(m_projectM.getPresetRating(index.row())));
		case Qt::DecorationRole:
			if ( index.column() == 1 )
				return ratingToIcon ( m_projectM.getPresetRating(index.row()) );
			else
				return QVariant();
		case QPlaylistModel::RatingRole:
			return QVariant (  m_projectM.getPresetRating(index.row())  );
		case Qt::BackgroundRole:
			if (!m_projectM.selectedPresetIndex(pos))
				return QVariant();
			if (m_projectM.isPresetLocked() && ( index.row() == pos ) )
				return Qt::red;
			if (!m_projectM.isPresetLocked() && ( index.row() == pos ) )
				return Qt::green;
			return QVariant();
		case QPlaylistModel::URLInfoRole:
			return QVariant ( QString ( m_projectM.getPresetURL ( index.row() ).c_str() ) );
		default:
			return QVariant();
	}
}

QVariant QPlaylistModel::headerData ( int section, Qt::Orientation orientation, int role ) const
{

	if ( orientation == Qt::Vertical )
		return QAbstractTableModel::headerData ( section, orientation, role );
	if ( ( section == 0 ) && ( role == Qt::DisplayRole ) )
		return QString ( tr ( "Preset" ) );
	if ( ( section == 1 ) && ( role == Qt::DisplayRole ) )
		return QString ( tr ( "Rating" ) );

	return QAbstractTableModel::headerData ( section, orientation, role );
}

int QPlaylistModel::rowCount ( const QModelIndex & parent ) const
{
	return m_projectM.getPlaylistSize();
}

int QPlaylistModel::columnCount ( const QModelIndex & parent ) const
{

	if ( rowCount() > 0 )
		return 2;
	else
		return 0;
}

void QPlaylistModel::appendRow ( const QString & presetURL, const QString & presetName, int rating )
{
	beginInsertRows ( QModelIndex(), rowCount(), rowCount() );
	m_projectM.addPresetURL ( presetURL.toStdString(), presetName.toStdString(), rating );
	endInsertRows();
}

void QPlaylistModel::insertRow (int index, const QString & presetURL, const QString & presetName, int rating)  {
	beginInsertRows ( QModelIndex(), index, index);
	m_projectM.insertPresetURL (index, presetURL.toStdString(), presetName.toStdString(), rating );
	endInsertRows();
}

bool QPlaylistModel::removeRows ( int row, int count, const QModelIndex & parent)   {

	beginRemoveRows ( QModelIndex(), row, count);

	for (int i = 0; i < count; i++) {
		m_projectM.removePreset (row );
	}
	endRemoveRows();
	return true;
}

bool QPlaylistModel::removeRow ( int index, const QModelIndex & parent)
{
	beginRemoveRows ( QModelIndex(), index, index );
	m_projectM.removePreset ( index );
	endRemoveRows();
	return true;
}

void QPlaylistModel::clear()
{
	clearItems();
	m_playlistName = "";
	m_playlistDesc = "";
}

void QPlaylistModel::clearItems()
{
	beginRemoveRows ( QModelIndex(), 0, rowCount()-1 );
	m_projectM.clearPlaylist();
	endRemoveRows();
}

bool QPlaylistModel::writePlaylist ( const QString & file ) {

	QFile qfile(file);

 	if (!qfile.open(QIODevice::WriteOnly)) {
		QMessageBox::warning (0, "Playlist Save Error", QString("There was a problem trying to save the playlist \"%1\".  You may not have permission to modify this file.").arg(file));
		return false;
	}

	XmlWriteFunctor writeFunctor(*this);

	QXmlPlaylistHandler::writePlaylist(&qfile, writeFunctor);
	return true;
}

bool QPlaylistModel::readPlaylist ( const QString & file )
{

	if (QFileInfo(file).isDir()) {
		if (!QDir(file).isReadable()) {
			QMessageBox::warning (0, "Playlist Directory Error", QString(tr("There was a problem trying to open the playlist directory \"%1\".  You may not have permission to open the directory.")).arg(file));
			return false;
		}
		foreach (QFileInfo info, QDir(file).entryInfoList()) {
			if (info.fileName().toLower().contains(".prjm") || info.fileName().toLower().contains(".milk"))
				appendRow(info.absoluteFilePath(), info.fileName(), 3);
		}
		return true;
	}

        QFile qfile(file);
 	if (!qfile.open(QIODevice::ReadOnly)) {
		QMessageBox::warning (0, "Playlist File Error", QString(tr("There was a problem trying to open the playlist \"%1\".  The file may no longer exist or you may not have permission to read the file.")).arg(file));
		return false;
	}

	XmlReadFunctor readFunctor(*this);

	if (QXmlPlaylistHandler::readPlaylist(&qfile, readFunctor) != QXmlStreamReader::NoError) {
		QMessageBox::warning ( 0, "Playlist Parse Error", QString(tr("There was a problem trying to parse the playlist \"%1\". Some of your playlist items may have loaded correctly, but don't expect miracles.")).arg(file));
	}

	return true;
}

<commit_msg>don't load files with *~ at end of them<commit_after>
#include <QIcon>
#include <QXmlStreamReader>
#include <QtDebug>
#include <QFileInfo>
#include <QDir>
#include <QMessageBox>

#include "qxmlplaylisthandler.hpp"
#include "qplaylistmodel.hpp"
#include <QMimeData>

QString QPlaylistModel::PRESET_MIME_TYPE("text/x-projectM-preset");

class XmlReadFunctor {
	public:
		XmlReadFunctor(QPlaylistModel & model) : m_model(model) {}

		inline void setPlaylistDesc(const QString & desc) {
			m_model.setPlaylistDesc(desc);
		}

		inline void appendItem(const QString & url, const QString & name, int rating) {
			m_model.appendRow(url, name, rating);
		}

	private:
		QPlaylistModel & m_model;

};

class XmlWriteFunctor {
	public:
		XmlWriteFunctor(QPlaylistModel & model) : m_model(model), m_index(0) {}

		inline const QString & playlistDesc() const {
			return m_model.playlistDesc();
		}

		inline bool nextItem(QString & url, int & rating) {

			if (m_index >= m_model.rowCount())
				return false;

			QModelIndex modelIndex = m_model.index(m_index, 0);
			url = m_model.data(modelIndex, QPlaylistModel::URLInfoRole).toString();
			rating = m_model.data(modelIndex, QPlaylistModel::RatingRole).toInt();
			m_index++;
			return true;
		}
	private:
		QPlaylistModel & m_model;
		int m_index;

};

QPlaylistModel::QPlaylistModel ( projectM & _projectM, QObject * parent ) :
		QAbstractTableModel ( parent ), m_projectM ( _projectM )
{

}

void QPlaylistModel::updateItemHighlights()
{
	if ( rowCount() == 0 )
		return;

	emit ( dataChanged ( this->index ( 0,0 ), this->index ( rowCount()-1,columnCount()-1 ) ) );
}

bool QPlaylistModel::setData ( const QModelIndex & index, const QVariant & value, int role )
{
	if ( role == QPlaylistModel::RatingRole )
	{
		m_projectM.changePresetRating(index.row(), value.toInt());
		emit ( dataChanged ( index, index ) );
		return true;
	}
	else
		return QAbstractTableModel::setData ( index, value, role );

}

Qt::ItemFlags QPlaylistModel::flags(const QModelIndex &index) const
{
	Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);

	if (index.isValid())
		return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
	else
		return Qt::ItemIsDropEnabled | defaultFlags;
}

 bool QPlaylistModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
				int row, int column, const QModelIndex &parent)
{
	qDebug() << "DROP";

	if (!data->hasFormat(PRESET_MIME_TYPE))
		return false;

	if (action == Qt::IgnoreAction)
		return true;

	if (column > 0)
		return false;

	return true;
}

QVariant QPlaylistModel::ratingToIcon ( int rating )  const
{
	switch ( rating )
	{
		case 1:
			return QVariant ( QIcon ( ":/images/icons/face0.png" ) );
		case 2:
			return QVariant ( QIcon ( ":/images/icons/face1.png" ) );
		case 3:
			return QVariant ( QIcon ( ":/images/icons/face2.png" ) );
		case 4:
			return QVariant ( QIcon ( ":/images/icons/face3.png" ) );
		case 5:
			return QVariant ( QIcon ( ":/images/icons/face4.png" ) );
		case 6:
			return QVariant ( QIcon ( ":/images/icons/face5.png" ) );
		default:
			if (rating < 0)
				return QVariant ( QIcon ( ":/images/icons/face0.png" ) );
			else
				return QVariant ( QIcon ( ":/images/icons/face5.png" ) );
	}
}

QString QPlaylistModel::getSillyRatingToolTip(int rating) {

switch (rating) {
	case 1:
		return QString("Rather watch grass grow than watch this");
	case 2:
		return QString("A very poor preset");
	case 3:
		return QString("Tolerable");
	case 4:
		return QString("Pretty good");
	case 5:
		return QString("Trippy eye candy");
	case 6:
		return QString("Crafted by a psychotic deity");
	default:
		if (rating <= 0 )
			return QString("So bad it literally makes other presets bad!");
		else
			return QString("Better than projectM itself!");
}
}

QVariant QPlaylistModel::data ( const QModelIndex & index, int role = Qt::DisplayRole ) const
{

	if (!index.isValid())
		return QVariant();

	unsigned int pos;

	switch ( role )
	{
		case Qt::DisplayRole:
			if ( index.column() == 0 )
				return QVariant ( QString ( m_projectM.getPresetName ( index.row() ).c_str() ) );
			else
				return ratingToIcon ( m_projectM.getPresetRating(index.row()) );
		case Qt::ToolTipRole:
			if ( index.column() == 0 )
				return QVariant ( QString ( m_projectM.getPresetName ( index.row() ).c_str() ) );
			else
				return QString ( getSillyRatingToolTip(m_projectM.getPresetRating(index.row())));
		case Qt::DecorationRole:
			if ( index.column() == 1 )
				return ratingToIcon ( m_projectM.getPresetRating(index.row()) );
			else
				return QVariant();
		case QPlaylistModel::RatingRole:
			return QVariant (  m_projectM.getPresetRating(index.row())  );
		case Qt::BackgroundRole:
			if (!m_projectM.selectedPresetIndex(pos))
				return QVariant();
			if (m_projectM.isPresetLocked() && ( index.row() == pos ) )
				return Qt::red;
			if (!m_projectM.isPresetLocked() && ( index.row() == pos ) )
				return Qt::green;
			return QVariant();
		case QPlaylistModel::URLInfoRole:
			return QVariant ( QString ( m_projectM.getPresetURL ( index.row() ).c_str() ) );
		default:
			return QVariant();
	}
}

QVariant QPlaylistModel::headerData ( int section, Qt::Orientation orientation, int role ) const
{

	if ( orientation == Qt::Vertical )
		return QAbstractTableModel::headerData ( section, orientation, role );
	if ( ( section == 0 ) && ( role == Qt::DisplayRole ) )
		return QString ( tr ( "Preset" ) );
	if ( ( section == 1 ) && ( role == Qt::DisplayRole ) )
		return QString ( tr ( "Rating" ) );

	return QAbstractTableModel::headerData ( section, orientation, role );
}

int QPlaylistModel::rowCount ( const QModelIndex & parent ) const
{
	return m_projectM.getPlaylistSize();
}

int QPlaylistModel::columnCount ( const QModelIndex & parent ) const
{

	if ( rowCount() > 0 )
		return 2;
	else
		return 0;
}

void QPlaylistModel::appendRow ( const QString & presetURL, const QString & presetName, int rating )
{
	beginInsertRows ( QModelIndex(), rowCount(), rowCount() );
	m_projectM.addPresetURL ( presetURL.toStdString(), presetName.toStdString(), rating );
	endInsertRows();
}

void QPlaylistModel::insertRow (int index, const QString & presetURL, const QString & presetName, int rating)  {
	beginInsertRows ( QModelIndex(), index, index);
	m_projectM.insertPresetURL (index, presetURL.toStdString(), presetName.toStdString(), rating );
	endInsertRows();
}

bool QPlaylistModel::removeRows ( int row, int count, const QModelIndex & parent)   {

	beginRemoveRows ( QModelIndex(), row, count);

	for (int i = 0; i < count; i++) {
		m_projectM.removePreset (row );
	}
	endRemoveRows();
	return true;
}

bool QPlaylistModel::removeRow ( int index, const QModelIndex & parent)
{
	beginRemoveRows ( QModelIndex(), index, index );
	m_projectM.removePreset ( index );
	endRemoveRows();
	return true;
}

void QPlaylistModel::clear()
{
	clearItems();
	m_playlistName = "";
	m_playlistDesc = "";
}

void QPlaylistModel::clearItems()
{
	beginRemoveRows ( QModelIndex(), 0, rowCount()-1 );
	m_projectM.clearPlaylist();
	endRemoveRows();
}

bool QPlaylistModel::writePlaylist ( const QString & file ) {

	QFile qfile(file);

 	if (!qfile.open(QIODevice::WriteOnly)) {
		QMessageBox::warning (0, "Playlist Save Error", QString("There was a problem trying to save the playlist \"%1\".  You may not have permission to modify this file.").arg(file));
		return false;
	}

	XmlWriteFunctor writeFunctor(*this);

	QXmlPlaylistHandler::writePlaylist(&qfile, writeFunctor);
	return true;
}

bool QPlaylistModel::readPlaylist ( const QString & file )
{

	if (QFileInfo(file).isDir()) {
		if (!QDir(file).isReadable()) {
			QMessageBox::warning (0, "Playlist Directory Error", QString(tr("There was a problem trying to open the playlist directory \"%1\".  You may not have permission to open the directory.")).arg(file));
			return false;
		}
		foreach (QFileInfo info, QDir(file).entryInfoList()) {
			if (info.fileName().toLower().endsWith(".prjm") || info.fileName().toLower().endsWith(".milk"))
				appendRow(info.absoluteFilePath(), info.fileName(), 3);
		}
		return true;
	}

        QFile qfile(file);
 	if (!qfile.open(QIODevice::ReadOnly)) {
		QMessageBox::warning (0, "Playlist File Error", QString(tr("There was a problem trying to open the playlist \"%1\".  The file may no longer exist or you may not have permission to read the file.")).arg(file));
		return false;
	}

	XmlReadFunctor readFunctor(*this);

	if (QXmlPlaylistHandler::readPlaylist(&qfile, readFunctor) != QXmlStreamReader::NoError) {
		QMessageBox::warning ( 0, "Playlist Parse Error", QString(tr("There was a problem trying to parse the playlist \"%1\". Some of your playlist items may have loaded correctly, but don't expect miracles.")).arg(file));
	}

	return true;
}

<|endoftext|>