<commit_before>//  (C) Copyright Gennadiy Rozental 2001-2010.
//  (C) Copyright Beman Dawes 2001.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision$
//
//  Description : defines abstract monitor interfaces and implements execution exception
//  The original Boost Test Library included an implementation detail function
//  named catch_exceptions() which caught otherwise uncaught C++ exceptions.
//  It was derived from an existing test framework by Beman Dawes.  The
//  intent was to expand later to catch other detectable but platform dependent
//  error events like Unix signals or Windows structured C exceptions.
//
//  Requests from early adopters of the Boost Test Library included
//  configurable levels of error message detail, elimination of templates,
//  separation of error reporting, and making the catch_exceptions() facilities
//  available as a public interface.  Support for unit testing also stretched
//  the function based design.  Implementation within the header became less
//  attractive due to the need to include many huge system dependent headers,
//  although still preferable in certain cases.
//
//  All those issues have been addressed by introducing the class-based
//  design presented here.
// ***************************************************************************

#ifndef BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER
#define BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER

// Boost.Test
#include <boost/test/detail/global_typedef.hpp>
#include <boost/test/detail/fwd_decl.hpp>
#include <boost/test/utils/callback.hpp>
#include <boost/test/utils/class_properties.hpp>

// Boost
#include <boost/shared_ptr.hpp>
#include <boost/scoped_array.hpp>
#include <boost/type.hpp>
#include <boost/cstdlib.hpp>

#include <boost/test/detail/suppress_warnings.hpp>

#ifdef BOOST_SEH_BASED_SIGNAL_HANDLING

// for the FP constants and control routines
#include <float.h>

#ifndef EM_INVALID
#define EM_INVALID _EM_INVALID
#endif

#ifndef EM_DENORMAL
#define EM_DENORMAL _EM_DENORMAL
#endif

#ifndef EM_ZERODIVIDE
#define EM_ZERODIVIDE _EM_ZERODIVIDE
#endif

#ifndef EM_OVERFLOW
#define EM_OVERFLOW _EM_OVERFLOW
#endif

#ifndef EM_UNDERFLOW
#define EM_UNDERFLOW _EM_UNDERFLOW
#endif

#ifndef MCW_EM
#define MCW_EM _MCW_EM
#endif

#else // based on ISO C standard

#ifndef __CYGWIN__
#include <fenv.h>
#endif

#endif

//____________________________________________________________________________//

namespace boost {

// ************************************************************************** //
// **************        detail::translator_holder_base        ************** //
// ************************************************************************** //

namespace detail {

class translator_holder_base;
typedef boost::shared_ptr<translator_holder_base> translator_holder_base_ptr;

class BOOST_TEST_DECL translator_holder_base {
protected:
    typedef boost::unit_test::const_string const_string;
public:
    // Constructor
    translator_holder_base( translator_holder_base_ptr next, const_string tag )
    : m_next( next )
    , m_tag( tag.begin(), tag.end() )
    {
    }

    // Destructor
    virtual     ~translator_holder_base() {}

    // translator holder interface
    // invokes the function F inside the try/catch guarding against specific exception
    virtual int operator()( unit_test::callback0<int> const& F ) = 0;
    // erases specific translator holder from the chain
    translator_holder_base_ptr erase( translator_holder_base_ptr this_, const_string tag )
    {
        if( m_next )
            m_next = m_next->erase( m_next, tag );

        return m_tag == tag ? m_next : this_;
    }
#ifndef BOOST_NO_RTTI
    virtual translator_holder_base_ptr erase( translator_holder_base_ptr this_, std::type_info const& ) = 0;
    template<typename ExceptionType>
    translator_holder_base_ptr erase( translator_holder_base_ptr this_, boost::type<ExceptionType>* = 0 )
    {
        if( m_next )
            m_next = m_next->erase<ExceptionType>( m_next );

        return erase( this_, typeid(ExceptionType) );
    }
#endif

protected:
    // Data members
    translator_holder_base_ptr  m_next;
    std::string                 m_tag;
};

} // namespace detail

// ************************************************************************** //
// **************              execution_exception             ************** //
// ************************************************************************** //

//  design rationale: fear of being out (or nearly out) of memory.

class BOOST_TEST_DECL execution_exception {
    typedef boost::unit_test::const_string const_string;
public:
    enum error_code {
        //  These values are sometimes used as program return codes.
        //  The particular values have been chosen to avoid conflicts with
        //  commonly used program return codes: values < 100 are often user
        //  assigned, values > 255 are sometimes used to report system errors.
        //  Gaps in values allow for orderly expansion.

        no_error               = 0,   // for completeness only; never returned
        user_error             = 200, // user reported non-fatal error
        cpp_exception_error    = 205, // see note (1) below
        system_error           = 210, // see note (2) below
        timeout_error          = 215, // only detectable on certain platforms
        user_fatal_error       = 220, // user reported fatal error
        system_fatal_error     = 225  // see note (2) below

        //  Note 1: Only uncaught C++ exceptions are treated as errors.
        //  If the application catches a C++ exception, it will never reach
        //  the execution_monitor.

        //  Note 2: These errors include Unix signals and Windows structured
        //  exceptions.  They are often initiated by hardware traps.
        //
        //  The implementation decides what is a fatal_system_exception and what is
        //  just a system_exception.  Fatal errors are so likely to have corrupted
        //  machine state (like a stack overflow or addressing exception) that it
        //  is unreasonable to continue execution.
    };

    struct BOOST_TEST_DECL location {
        explicit    location( char const* file_name = 0, size_t line_num = 0, char const* func = 0 );

        const_string    m_file_name;
        size_t          m_line_num;
        const_string    m_function;
    };

    // Constructor
    execution_exception( error_code ec_, const_string what_msg_, location const& location_ ); // max length 256 inc '\0'

    // Access methods
    error_code      code() const    { return m_error_code; }
    const_string    what() const    { return m_what; }
    location const& where() const   { return m_location; }

private:
    // Data members
    error_code      m_error_code;
    const_string    m_what;
    location        m_location;
}; // execution_exception

// ************************************************************************** //
// **************               execution_monitor              ************** //
// ************************************************************************** //

class BOOST_TEST_DECL execution_monitor {
    typedef boost::unit_test::const_string const_string;
public:
    // Constructor
    execution_monitor();

    // Public properties

    //  The p_catch_system_errors parameter specifies whether the monitor should
    //  try to catch system errors/exceptions that would cause program to crash
    //  in regular case
    unit_test::readwrite_property<bool> p_catch_system_errors;

    //  The p_auto_start_dbg parameter specifies whether the monitor should
    //  try to attach debugger in case of caught system error
    unit_test::readwrite_property<bool> p_auto_start_dbg;

    //  The p_timeout parameter specifies the seconds that elapse before
    //  a timer_error occurs.  May be ignored on some platforms.
    unit_test::readwrite_property<int>  p_timeout;

    //  The p_use_alt_stack parameter specifies whether the monitor should
    //  use alternative stack for the signal catching
    unit_test::readwrite_property<bool> p_use_alt_stack;

    //  The p_detect_fp_exceptions parameter specifies whether the monitor should
    //  try to detect hardware floating point exceptions (!= 0), and which specific exception to catch
    unit_test::readwrite_property<unsigned> p_detect_fp_exceptions;

    int         execute( unit_test::callback0<int> const& F );
    //  Returns:  Value returned by function call F().
    //
    //  Effects:  Calls executes supplied function F inside a try/catch block which also may
    //  include other unspecified platform dependent error detection code.
    //
    //  Throws: execution_exception on an uncaught C++ exception,
    //  a hardware or software signal, trap, or other exception.
    //
    //  Note: execute() doesn't consider it an error for F to return a non-zero value.

    // register custom (user supplied) exception translator
    template<typename ExceptionType, typename ExceptionTranslator>
    void        register_exception_translator( ExceptionTranslator const& tr, const_string tag = const_string(), boost::type<ExceptionType>* = 0 );

    // erase custom exception translator
    void        erase_exception_translator( const_string tag )
    {
        m_custom_translators = m_custom_translators->erase( m_custom_translators, tag );
    }
    template<typename ExceptionType>
    void        erase_exception_translator( boost::type<ExceptionType>* = 0 )
    {
        m_custom_translators = m_custom_translators->erase<ExceptionType>( m_custom_translators );
    }

private:
    // implementation helpers
    int         catch_signals( unit_test::callback0<int> const& F );

    // Data members
    detail::translator_holder_base_ptr  m_custom_translators;
    boost::scoped_array<char>           m_alt_stack;
}; // execution_monitor

// ************************************************************************** //
// **************          detail::translator_holder           ************** //
// ************************************************************************** //

namespace detail {

template<typename ExceptionType, typename ExceptionTranslator>
class translator_holder : public translator_holder_base
{
public:
    explicit    translator_holder( ExceptionTranslator const& tr, translator_holder_base_ptr& next, const_string tag = const_string() )
    : translator_holder_base( next, tag ), m_translator( tr ) {}

    // translator holder interface
    virtual int operator()( unit_test::callback0<int> const& F )
    {
        try {
            return m_next ? (*m_next)( F ) : F();
        } catch( ExceptionType const& e ) {
            m_translator( e );
            return boost::exit_exception_failure;
        }
    }
#ifndef BOOST_NO_RTTI
    virtual translator_holder_base_ptr erase( translator_holder_base_ptr this_, std::type_info const& ti )
    {
        return ti == typeid(ExceptionType) ? m_next : this_;
    }
#endif

private:
    // Data members
    ExceptionTranslator m_translator;
};

} // namespace detail

template<typename ExceptionType, typename ExceptionTranslator>
void
execution_monitor::register_exception_translator( ExceptionTranslator const& tr, const_string tag, boost::type<ExceptionType>* )
{
    m_custom_translators.reset(
        new detail::translator_holder<ExceptionType,ExceptionTranslator>( tr, m_custom_translators, tag ) );
}

// ************************************************************************** //
// **************               execution_aborted              ************** //
// ************************************************************************** //

struct execution_aborted {};

// ************************************************************************** //
// **************                  system_error                ************** //
// ************************************************************************** //

class system_error {
public:
    // Constructor
    explicit    system_error( char const* exp );

    unit_test::readonly_property<long>          p_errno;
    unit_test::readonly_property<char const*>   p_failed_exp;
};

#define BOOST_TEST_SYS_ASSERT( exp ) if( (exp) ) ; else throw ::boost::system_error( BOOST_STRINGIZE( exp ) )

// ************************************************************************** //
// **************Floating point exception management interface ************** //
// ************************************************************************** //

namespace fpe {

enum masks {
    BOOST_FPE_OFF       = 0,

#ifdef BOOST_SEH_BASED_SIGNAL_HANDLING
    BOOST_FPE_DIVBYZERO = EM_ZERODIVIDE,
    BOOST_FPE_INEXACT   = EM_INEXACT,
    BOOST_FPE_INVALID   = EM_INVALID,
    BOOST_FPE_OVERFLOW  = EM_OVERFLOW,
    BOOST_FPE_UNDERFLOW = EM_UNDERFLOW|EM_DENORMAL,

    BOOST_FPE_ALL       = MCW_EM,
#elif defined(__CYGWIN__)
    BOOST_FPE_ALL       = 1
#else
    BOOST_FPE_DIVBYZERO = FE_DIVBYZERO,
    BOOST_FPE_INEXACT   = FE_INEXACT,
    BOOST_FPE_INVALID   = FE_INVALID,
    BOOST_FPE_OVERFLOW  = FE_OVERFLOW,
    BOOST_FPE_UNDERFLOW = FE_UNDERFLOW,

    BOOST_FPE_ALL       = FE_ALL_EXCEPT,
#endif
    BOOST_FPE_INV       = BOOST_FPE_ALL+1
};

// return the previous set of enabled exceptions when successful, and BOOST_FPE_INV otherwise
unsigned BOOST_TEST_DECL enable( unsigned mask );
unsigned BOOST_TEST_DECL disable( unsigned mask );

} // namespace fpe

}  // namespace boost

//____________________________________________________________________________//

#include <boost/test/detail/enable_warnings.hpp>

#endif
<commit_msg>cygwin fix<commit_after>//  (C) Copyright Gennadiy Rozental 2001-2010.
//  (C) Copyright Beman Dawes 2001.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision$
//
//  Description : defines abstract monitor interfaces and implements execution exception
//  The original Boost Test Library included an implementation detail function
//  named catch_exceptions() which caught otherwise uncaught C++ exceptions.
//  It was derived from an existing test framework by Beman Dawes.  The
//  intent was to expand later to catch other detectable but platform dependent
//  error events like Unix signals or Windows structured C exceptions.
//
//  Requests from early adopters of the Boost Test Library included
//  configurable levels of error message detail, elimination of templates,
//  separation of error reporting, and making the catch_exceptions() facilities
//  available as a public interface.  Support for unit testing also stretched
//  the function based design.  Implementation within the header became less
//  attractive due to the need to include many huge system dependent headers,
//  although still preferable in certain cases.
//
//  All those issues have been addressed by introducing the class-based
//  design presented here.
// ***************************************************************************

#ifndef BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER
#define BOOST_TEST_EXECUTION_MONITOR_HPP_071894GER

// Boost.Test
#include <boost/test/detail/global_typedef.hpp>
#include <boost/test/detail/fwd_decl.hpp>
#include <boost/test/utils/callback.hpp>
#include <boost/test/utils/class_properties.hpp>

// Boost
#include <boost/shared_ptr.hpp>
#include <boost/scoped_array.hpp>
#include <boost/type.hpp>
#include <boost/cstdlib.hpp>

#include <boost/test/detail/suppress_warnings.hpp>

#ifdef BOOST_SEH_BASED_SIGNAL_HANDLING

// for the FP constants and control routines
#include <float.h>

#ifndef EM_INVALID
#define EM_INVALID _EM_INVALID
#endif

#ifndef EM_DENORMAL
#define EM_DENORMAL _EM_DENORMAL
#endif

#ifndef EM_ZERODIVIDE
#define EM_ZERODIVIDE _EM_ZERODIVIDE
#endif

#ifndef EM_OVERFLOW
#define EM_OVERFLOW _EM_OVERFLOW
#endif

#ifndef EM_UNDERFLOW
#define EM_UNDERFLOW _EM_UNDERFLOW
#endif

#ifndef MCW_EM
#define MCW_EM _MCW_EM
#endif

#else // based on ISO C standard

#ifndef __CYGWIN__
#include <fenv.h>
#endif

#endif

//____________________________________________________________________________//

namespace boost {

// ************************************************************************** //
// **************        detail::translator_holder_base        ************** //
// ************************************************************************** //

namespace detail {

class translator_holder_base;
typedef boost::shared_ptr<translator_holder_base> translator_holder_base_ptr;

class BOOST_TEST_DECL translator_holder_base {
protected:
    typedef boost::unit_test::const_string const_string;
public:
    // Constructor
    translator_holder_base( translator_holder_base_ptr next, const_string tag )
    : m_next( next )
    , m_tag( tag.begin(), tag.end() )
    {
    }

    // Destructor
    virtual     ~translator_holder_base() {}

    // translator holder interface
    // invokes the function F inside the try/catch guarding against specific exception
    virtual int operator()( unit_test::callback0<int> const& F ) = 0;
    // erases specific translator holder from the chain
    translator_holder_base_ptr erase( translator_holder_base_ptr this_, const_string tag )
    {
        if( m_next )
            m_next = m_next->erase( m_next, tag );

        return m_tag == tag ? m_next : this_;
    }
#ifndef BOOST_NO_RTTI
    virtual translator_holder_base_ptr erase( translator_holder_base_ptr this_, std::type_info const& ) = 0;
    template<typename ExceptionType>
    translator_holder_base_ptr erase( translator_holder_base_ptr this_, boost::type<ExceptionType>* = 0 )
    {
        if( m_next )
            m_next = m_next->erase<ExceptionType>( m_next );

        return erase( this_, typeid(ExceptionType) );
    }
#endif

protected:
    // Data members
    translator_holder_base_ptr  m_next;
    std::string                 m_tag;
};

} // namespace detail

// ************************************************************************** //
// **************              execution_exception             ************** //
// ************************************************************************** //

//  design rationale: fear of being out (or nearly out) of memory.

class BOOST_TEST_DECL execution_exception {
    typedef boost::unit_test::const_string const_string;
public:
    enum error_code {
        //  These values are sometimes used as program return codes.
        //  The particular values have been chosen to avoid conflicts with
        //  commonly used program return codes: values < 100 are often user
        //  assigned, values > 255 are sometimes used to report system errors.
        //  Gaps in values allow for orderly expansion.

        no_error               = 0,   // for completeness only; never returned
        user_error             = 200, // user reported non-fatal error
        cpp_exception_error    = 205, // see note (1) below
        system_error           = 210, // see note (2) below
        timeout_error          = 215, // only detectable on certain platforms
        user_fatal_error       = 220, // user reported fatal error
        system_fatal_error     = 225  // see note (2) below

        //  Note 1: Only uncaught C++ exceptions are treated as errors.
        //  If the application catches a C++ exception, it will never reach
        //  the execution_monitor.

        //  Note 2: These errors include Unix signals and Windows structured
        //  exceptions.  They are often initiated by hardware traps.
        //
        //  The implementation decides what is a fatal_system_exception and what is
        //  just a system_exception.  Fatal errors are so likely to have corrupted
        //  machine state (like a stack overflow or addressing exception) that it
        //  is unreasonable to continue execution.
    };

    struct BOOST_TEST_DECL location {
        explicit    location( char const* file_name = 0, size_t line_num = 0, char const* func = 0 );

        const_string    m_file_name;
        size_t          m_line_num;
        const_string    m_function;
    };

    // Constructor
    execution_exception( error_code ec_, const_string what_msg_, location const& location_ ); // max length 256 inc '\0'

    // Access methods
    error_code      code() const    { return m_error_code; }
    const_string    what() const    { return m_what; }
    location const& where() const   { return m_location; }

private:
    // Data members
    error_code      m_error_code;
    const_string    m_what;
    location        m_location;
}; // execution_exception

// ************************************************************************** //
// **************               execution_monitor              ************** //
// ************************************************************************** //

class BOOST_TEST_DECL execution_monitor {
    typedef boost::unit_test::const_string const_string;
public:
    // Constructor
    execution_monitor();

    // Public properties

    //  The p_catch_system_errors parameter specifies whether the monitor should
    //  try to catch system errors/exceptions that would cause program to crash
    //  in regular case
    unit_test::readwrite_property<bool> p_catch_system_errors;

    //  The p_auto_start_dbg parameter specifies whether the monitor should
    //  try to attach debugger in case of caught system error
    unit_test::readwrite_property<bool> p_auto_start_dbg;

    //  The p_timeout parameter specifies the seconds that elapse before
    //  a timer_error occurs.  May be ignored on some platforms.
    unit_test::readwrite_property<int>  p_timeout;

    //  The p_use_alt_stack parameter specifies whether the monitor should
    //  use alternative stack for the signal catching
    unit_test::readwrite_property<bool> p_use_alt_stack;

    //  The p_detect_fp_exceptions parameter specifies whether the monitor should
    //  try to detect hardware floating point exceptions (!= 0), and which specific exception to catch
    unit_test::readwrite_property<unsigned> p_detect_fp_exceptions;

    int         execute( unit_test::callback0<int> const& F );
    //  Returns:  Value returned by function call F().
    //
    //  Effects:  Calls executes supplied function F inside a try/catch block which also may
    //  include other unspecified platform dependent error detection code.
    //
    //  Throws: execution_exception on an uncaught C++ exception,
    //  a hardware or software signal, trap, or other exception.
    //
    //  Note: execute() doesn't consider it an error for F to return a non-zero value.

    // register custom (user supplied) exception translator
    template<typename ExceptionType, typename ExceptionTranslator>
    void        register_exception_translator( ExceptionTranslator const& tr, const_string tag = const_string(), boost::type<ExceptionType>* = 0 );

    // erase custom exception translator
    void        erase_exception_translator( const_string tag )
    {
        m_custom_translators = m_custom_translators->erase( m_custom_translators, tag );
    }
    template<typename ExceptionType>
    void        erase_exception_translator( boost::type<ExceptionType>* = 0 )
    {
        m_custom_translators = m_custom_translators->erase<ExceptionType>( m_custom_translators );
    }

private:
    // implementation helpers
    int         catch_signals( unit_test::callback0<int> const& F );

    // Data members
    detail::translator_holder_base_ptr  m_custom_translators;
    boost::scoped_array<char>           m_alt_stack;
}; // execution_monitor

// ************************************************************************** //
// **************          detail::translator_holder           ************** //
// ************************************************************************** //

namespace detail {

template<typename ExceptionType, typename ExceptionTranslator>
class translator_holder : public translator_holder_base
{
public:
    explicit    translator_holder( ExceptionTranslator const& tr, translator_holder_base_ptr& next, const_string tag = const_string() )
    : translator_holder_base( next, tag ), m_translator( tr ) {}

    // translator holder interface
    virtual int operator()( unit_test::callback0<int> const& F )
    {
        try {
            return m_next ? (*m_next)( F ) : F();
        } catch( ExceptionType const& e ) {
            m_translator( e );
            return boost::exit_exception_failure;
        }
    }
#ifndef BOOST_NO_RTTI
    virtual translator_holder_base_ptr erase( translator_holder_base_ptr this_, std::type_info const& ti )
    {
        return ti == typeid(ExceptionType) ? m_next : this_;
    }
#endif

private:
    // Data members
    ExceptionTranslator m_translator;
};

} // namespace detail

template<typename ExceptionType, typename ExceptionTranslator>
void
execution_monitor::register_exception_translator( ExceptionTranslator const& tr, const_string tag, boost::type<ExceptionType>* )
{
    m_custom_translators.reset(
        new detail::translator_holder<ExceptionType,ExceptionTranslator>( tr, m_custom_translators, tag ) );
}

// ************************************************************************** //
// **************               execution_aborted              ************** //
// ************************************************************************** //

struct execution_aborted {};

// ************************************************************************** //
// **************                  system_error                ************** //
// ************************************************************************** //

class system_error {
public:
    // Constructor
    explicit    system_error( char const* exp );

    unit_test::readonly_property<long>          p_errno;
    unit_test::readonly_property<char const*>   p_failed_exp;
};

#define BOOST_TEST_SYS_ASSERT( exp ) if( (exp) ) ; else throw ::boost::system_error( BOOST_STRINGIZE( exp ) )

// ************************************************************************** //
// **************Floating point exception management interface ************** //
// ************************************************************************** //

namespace fpe {

enum masks {
    BOOST_FPE_OFF       = 0,

#ifdef BOOST_SEH_BASED_SIGNAL_HANDLING
    BOOST_FPE_DIVBYZERO = EM_ZERODIVIDE,
    BOOST_FPE_INEXACT   = EM_INEXACT,
    BOOST_FPE_INVALID   = EM_INVALID,
    BOOST_FPE_OVERFLOW  = EM_OVERFLOW,
    BOOST_FPE_UNDERFLOW = EM_UNDERFLOW|EM_DENORMAL,

    BOOST_FPE_ALL       = MCW_EM,
#elif defined(__CYGWIN__)
    BOOST_FPE_ALL       = 1,
#else
    BOOST_FPE_DIVBYZERO = FE_DIVBYZERO,
    BOOST_FPE_INEXACT   = FE_INEXACT,
    BOOST_FPE_INVALID   = FE_INVALID,
    BOOST_FPE_OVERFLOW  = FE_OVERFLOW,
    BOOST_FPE_UNDERFLOW = FE_UNDERFLOW,

    BOOST_FPE_ALL       = FE_ALL_EXCEPT,
#endif
    BOOST_FPE_INV       = BOOST_FPE_ALL+1
};

// return the previous set of enabled exceptions when successful, and BOOST_FPE_INV otherwise
unsigned BOOST_TEST_DECL enable( unsigned mask );
unsigned BOOST_TEST_DECL disable( unsigned mask );

} // namespace fpe

}  // namespace boost

//____________________________________________________________________________//

#include <boost/test/detail/enable_warnings.hpp>

#endif
<|endoftext|>


<commit_before>#include <image_cloud/common/small_helpers.hpp>
#include <image_cloud/common/type.hpp>

#include <pcl/common/common.h>
#include <image_geometry/pinhole_camera_model.h>
#include <opencv2/core/core.hpp>

#ifndef PROJECT_2D_H_
#define PROJECT_2D_H_

namespace project2d
{

inline void
project_2d(
		const image_geometry::PinholeCameraModel &camera_model,
		const pcl::PointCloud<pcl::PointXYZI> &in,
		pcl::PointCloud<pcl::PointXY> &out_2d,
		pcl::PointCloud<pcl::PointXYZI> &out_3d,
		unsigned int camera_width = 1024,
		unsigned int camera_height = 768
		)
{
	BOOST_FOREACH (const pcl::PointXYZI& pt, in.points)
	{
		if( pt.z > 1) { // min distance from camera 1m

			cv::Point2i point_image = camera_model.project3dToPixel(cv::Point3d(pt.x, pt.y, pt.z));

			if( between<int>(0, point_image.x, camera_width )
				&& between<int>( 0, point_image.y, camera_height )
			)
			{
				// Point in image push to 2d and 3d point
				pcl::PointXY pt_2d;
				pt_2d.x = point_image.x;
				pt_2d.y = point_image.y;
				out_2d.push_back(pt_2d);
				out_3d.push_back(pt);
			}
		}
	}
}

enum Field{
	INTENSITY = 0,
	DEPTH = 1
};

template <typename PointT>
void
project_2d(
		const image_geometry::PinholeCameraModel &camera_model,
		const pcl::PointCloud<PointT> &in,
		cv::Mat &image,
		Field field = DEPTH,
		int point_size = 1,
		float min_distance = 1
		)
{
	BOOST_FOREACH (const PointT& pt, in.points)
	{
		if( pt.z > min_distance) { // min distance from camera 1m

			cv::Point2i point_image = camera_model.project3dToPixel(cv::Point3d(pt.x, pt.y, pt.z));

			if( between<int>(0, point_image.x, image.cols )
				&& between<int>( 0, point_image.y, image.rows )
			)
			{
				switch(field){
					default:
					case DEPTH:
							cv::circle(image, point_image, point_size, cv::Scalar(pt.z), -1);
						break;
					case INTENSITY:
							cv::circle(image, point_image, point_size, cv::Scalar(pt.intensity), -1);
						break;
				}
			}
		}
	}
}

template <typename PointT>
void
project_2d(
		const image_geometry::PinholeCameraModel &camera_model,
		pcl::PointCloud<PointT> &in,
		std::vector<std::vector<boost::shared_ptr<pcl::PointXYZI> > > &out,
		int image_width,
		int image_height)
{
		BOOST_FOREACH (pcl::PointXYZI& pt, in.points){
			if( pt.z > 1) { // min distance from camera 1m

				cv::Point2i point_image = camera_model.project3dToPixel(cv::Point3d(pt.x, pt.y, pt.z));

				if( between<int>(0, point_image.x, image_width )
					&& between<int>( 0, point_image.y, image_height )
				)
				{
					// Point in image push to 2d and 3d point
					out[point_image.x][point_image.y].reset(new pcl::PointXYZI(pt));
				}
			}
		}
}

template <typename PointT>
void
project_2d(
		const image_geometry::PinholeCameraModel &camera_model,
		pcl::PointCloud<PointT> &in,
		std::vector<std::vector<boost::shared_ptr<pcl::PointXYZI> > > &out_vector,
		Projected_pointcloud<PointT> &out,
		int image_width,
		int image_height)
{
		assert(out_vector.size() == image_width);
		assert(out_vector[0].size() == image_height);
		out.image_size.width = image_width;
		out.image_size.height = image_height;

		BOOST_FOREACH (pcl::PointXYZI& pt, in.points){
			if( pt.z > 1) { // min distance from camera 1m

				cv::Point2i point_image = camera_model.project3dToPixel(cv::Point3d(pt.x, pt.y, pt.z));

				if( between<int>(0, point_image.x, image_width )
					&& between<int>( 0, point_image.y, image_height )
				)
				{
					// Point in image push to 2d and 3d point
					out_vector[point_image.x][point_image.y].reset(new pcl::PointXYZI(pt));
					out.points.push_back(Projected_Point<PointT>(pt, point_image));
				}
			}
		}
}

template <typename PointT>
inline void
project_2d(
		const image_geometry::PinholeCameraModel &camera_model,
		pcl::PointCloud<PointT> &in,
		Projected_pointcloud<PointT> &out,
		int image_width,
		int image_height)
{
		out.image_size.width = image_width;
		out.image_size.height = image_height;

		BOOST_FOREACH (pcl::PointXYZI& pt, in.points){
			if( pt.z > 1) { // min distance from camera 1m

				cv::Point2i point_image = camera_model.project3dToPixel(cv::Point3d(pt.x, pt.y, pt.z));

				if( between<int>(0, point_image.x, image_width )
					&& between<int>( 0, point_image.y, image_height )
				)
				{
					out.points.push_back(Projected_Point<PointT>(pt, point_image));
				}
			}
		}
}

template <typename PointT>
void
project_2d(
		std::vector<std::vector<boost::shared_ptr<PointT> > > &in,
		cv::Mat &out,
		Field field = INTENSITY,
		int point_size = 1
		)
{
		for(int y = 0; y < in[0].size(); y++)
		{
			for(int x = 0; x < in.size(); x++)
			{
				cv::Point3i value;
				if( in[x][y]){ /* found something */
					switch(field){
						default:
						case DEPTH:
								cv::circle(out, cv::Point2i(x,y), point_size, cv::Scalar(in[x][y]->z), -1);
							break;
						case INTENSITY:
								cv::circle(out, cv::Point2i(x,y), point_size, cv::Scalar(in[x][y]->intensity), -1);
							break;
					}
				}
			}
		}
}

}
#endif
<commit_msg>made function inline<commit_after>#include <image_cloud/common/small_helpers.hpp>
#include <image_cloud/common/type.hpp>

#include <pcl/common/common.h>
#include <image_geometry/pinhole_camera_model.h>
#include <opencv2/core/core.hpp>

#ifndef PROJECT_2D_H_
#define PROJECT_2D_H_

namespace project2d
{

inline void
project_2d(
		const image_geometry::PinholeCameraModel &camera_model,
		const pcl::PointCloud<pcl::PointXYZI> &in,
		pcl::PointCloud<pcl::PointXY> &out_2d,
		pcl::PointCloud<pcl::PointXYZI> &out_3d,
		unsigned int camera_width = 1024,
		unsigned int camera_height = 768
		)
{
	BOOST_FOREACH (const pcl::PointXYZI& pt, in.points)
	{
		if( pt.z > 1) { // min distance from camera 1m

			cv::Point2i point_image = camera_model.project3dToPixel(cv::Point3d(pt.x, pt.y, pt.z));

			if( between<int>(0, point_image.x, camera_width )
				&& between<int>( 0, point_image.y, camera_height )
			)
			{
				// Point in image push to 2d and 3d point
				pcl::PointXY pt_2d;
				pt_2d.x = point_image.x;
				pt_2d.y = point_image.y;
				out_2d.push_back(pt_2d);
				out_3d.push_back(pt);
			}
		}
	}
}

enum Field{
	INTENSITY = 0,
	DEPTH = 1
};

template <typename PointT>
inline void
project_2d(
		const image_geometry::PinholeCameraModel &camera_model,
		const pcl::PointCloud<PointT> &in,
		cv::Mat &image,
		Field field = DEPTH,
		int point_size = 1,
		float min_distance = 1
		)
{
	BOOST_FOREACH (const PointT& pt, in.points)
	{
		if( pt.z > min_distance) { // min distance from camera 1m

			cv::Point2i point_image = camera_model.project3dToPixel(cv::Point3d(pt.x, pt.y, pt.z));

			if( between<int>(0, point_image.x, image.cols )
				&& between<int>( 0, point_image.y, image.rows )
			)
			{
				switch(field){
					default:
					case DEPTH:
							cv::circle(image, point_image, point_size, cv::Scalar(pt.z), -1);
						break;
					case INTENSITY:
							cv::circle(image, point_image, point_size, cv::Scalar(pt.intensity), -1);
						break;
				}
			}
		}
	}
}

template <typename PointT>
inline void
project_2d(
		const image_geometry::PinholeCameraModel &camera_model,
		pcl::PointCloud<PointT> &in,
		std::vector<std::vector<boost::shared_ptr<pcl::PointXYZI> > > &out,
		int image_width,
		int image_height)
{
		BOOST_FOREACH (pcl::PointXYZI& pt, in.points){
			if( pt.z > 1) { // min distance from camera 1m

				cv::Point2i point_image = camera_model.project3dToPixel(cv::Point3d(pt.x, pt.y, pt.z));

				if( between<int>(0, point_image.x, image_width )
					&& between<int>( 0, point_image.y, image_height )
				)
				{
					// Point in image push to 2d and 3d point
					out[point_image.x][point_image.y].reset(new pcl::PointXYZI(pt));
				}
			}
		}
}

template <typename PointT>
inline void
project_2d(
		const image_geometry::PinholeCameraModel &camera_model,
		pcl::PointCloud<PointT> &in,
		std::vector<std::vector<boost::shared_ptr<pcl::PointXYZI> > > &out_vector,
		Projected_pointcloud<PointT> &out,
		int image_width,
		int image_height)
{
		assert(out_vector.size() == image_width);
		assert(out_vector[0].size() == image_height);
		out.image_size.width = image_width;
		out.image_size.height = image_height;

		BOOST_FOREACH (pcl::PointXYZI& pt, in.points){
			if( pt.z > 1) { // min distance from camera 1m

				cv::Point2i point_image = camera_model.project3dToPixel(cv::Point3d(pt.x, pt.y, pt.z));

				if( between<int>(0, point_image.x, image_width )
					&& between<int>( 0, point_image.y, image_height )
				)
				{
					// Point in image push to 2d and 3d point
					out_vector[point_image.x][point_image.y].reset(new pcl::PointXYZI(pt));
					out.points.push_back(Projected_Point<PointT>(pt, point_image));
				}
			}
		}
}

template <typename PointT>
inline void
project_2d(
		const image_geometry::PinholeCameraModel &camera_model,
		pcl::PointCloud<PointT> &in,
		Projected_pointcloud<PointT> &out,
		int image_width,
		int image_height)
{
		out.image_size.width = image_width;
		out.image_size.height = image_height;

		BOOST_FOREACH (pcl::PointXYZI& pt, in.points){
			if( pt.z > 1) { // min distance from camera 1m

				cv::Point2i point_image = camera_model.project3dToPixel(cv::Point3d(pt.x, pt.y, pt.z));

				if( between<int>(0, point_image.x, image_width )
					&& between<int>( 0, point_image.y, image_height )
				)
				{
					out.points.push_back(Projected_Point<PointT>(pt, point_image));
				}
			}
		}
}

template <typename PointT>
inline void
project_2d(
		std::vector<std::vector<boost::shared_ptr<PointT> > > &in,
		cv::Mat &out,
		Field field = INTENSITY,
		int point_size = 1
		)
{
		for(int y = 0; y < in[0].size(); y++)
		{
			for(int x = 0; x < in.size(); x++)
			{
				cv::Point3i value;
				if( in[x][y]){ /* found something */
					switch(field){
						default:
						case DEPTH:
								cv::circle(out, cv::Point2i(x,y), point_size, cv::Scalar(in[x][y]->z), -1);
							break;
						case INTENSITY:
								cv::circle(out, cv::Point2i(x,y), point_size, cv::Scalar(in[x][y]->intensity), -1);
							break;
					}
				}
			}
		}
}

}
#endif
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED
#define TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED

#include "libtorrent/socket.hpp"
#include "libtorrent/invariant_check.hpp"

#include <boost/shared_ptr.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/integer_traits.hpp>
#include <boost/thread/mutex.hpp>
#include <deque>

using boost::weak_ptr;
using boost::shared_ptr;
using boost::intrusive_ptr;
using boost::bind;

namespace libtorrent {

// the maximum block of bandwidth quota to
// hand out is 33kB. The block size may
// be smaller on lower limits
enum
{
	max_bandwidth_block_size = 33000,
	min_bandwidth_block_size = 400
};

const time_duration bw_window_size = seconds(1);

template<class PeerConnection, class Torrent>
struct history_entry
{
	history_entry(intrusive_ptr<PeerConnection> p, weak_ptr<Torrent> t
		, int a, ptime exp)
		: expires_at(exp), amount(a), peer(p), tor(t) {}
	ptime expires_at;
	int amount;
	intrusive_ptr<PeerConnection> peer;
	weak_ptr<Torrent> tor;
};

template<class PeerConnection>
struct bw_queue_entry
{
	bw_queue_entry(boost::intrusive_ptr<PeerConnection> const& pe
		, int blk, bool no_prio)
		: peer(pe), max_block_size(blk), non_prioritized(no_prio) {}
	boost::intrusive_ptr<PeerConnection> peer;
	int max_block_size;
	bool non_prioritized;
};

// member of peer_connection
struct bandwidth_limit
{
	static const int inf = boost::integer_traits<int>::const_max;

	bandwidth_limit() throw()
		: m_quota_left(0)
		, m_local_limit(inf)
		, m_current_rate(0)
	{}

	void throttle(int limit) throw()
	{
		m_local_limit = limit;
	}

	int throttle() const throw()
	{
		return m_local_limit;
	}

	void assign(int amount) throw()
	{
		assert(amount > 0);
		m_current_rate += amount;
		m_quota_left += amount;
	}

	void use_quota(int amount) throw()
	{
		assert(amount <= m_quota_left);
		m_quota_left -= amount;
	}

	int quota_left() const throw()
	{
		return (std::max)(m_quota_left, 0);
	}

	void expire(int amount) throw()
	{
		assert(amount >= 0);
		m_current_rate -= amount;
	}

	int max_assignable() const throw()
	{
		if (m_local_limit == inf) return inf;
		if (m_local_limit <= m_current_rate) return 0;
		return m_local_limit - m_current_rate;
	}

private:

	// this is the amount of bandwidth we have
	// been assigned without using yet. i.e.
	// the bandwidth that we use up every time
	// we receive or send a message. Once this
	// hits zero, we need to request more
	// bandwidth from the torrent which
	// in turn will request bandwidth from
	// the bandwidth manager
	int m_quota_left;

	// the local limit is the number of bytes
	// per window size we are allowed to use.
	int m_local_limit;

	// the current rate is the number of
	// bytes we have been assigned within
	// the window size.
	int m_current_rate;
};

template<class T>
T clamp(T val, T ceiling, T floor) throw()
{
	assert(ceiling >= floor);
	if (val >= ceiling) return ceiling;
	else if (val <= floor) return floor;
	return val;
}

template<class PeerConnection, class Torrent>
struct bandwidth_manager
{
	bandwidth_manager(io_service& ios, int channel) throw()
		: m_ios(ios)
		, m_history_timer(m_ios)
		, m_limit(bandwidth_limit::inf)
		, m_current_quota(0)
		, m_channel(channel)
	{}

	void throttle(int limit) throw()
	{
		mutex_t::scoped_lock l(m_mutex);
		assert(limit >= 0);
		m_limit = limit;
	}

	int throttle() const throw()
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_limit;
	}

	// non prioritized means that, if there's a line for bandwidth,
	// others will cut in front of the non-prioritized peers.
	// this is used by web seeds
	void request_bandwidth(intrusive_ptr<PeerConnection> peer
		, int blk
		, bool non_prioritized) throw()
	{
		INVARIANT_CHECK;
		assert(blk > 0);

		assert(!peer->ignore_bandwidth_limits());

		// make sure this peer isn't already in line
		// waiting for bandwidth
#ifndef NDEBUG
		for (typename queue_t::iterator i = m_queue.begin()
			, end(m_queue.end()); i != end; ++i)
		{
			assert(i->peer < peer || peer < i->peer);
		}
#endif

		assert(peer->max_assignable_bandwidth(m_channel) > 0);
		boost::shared_ptr<Torrent> t = peer->associated_torrent().lock();
		m_queue.push_back(bw_queue_entry<PeerConnection>(peer, blk, non_prioritized));
		if (!non_prioritized)
		{
			typename queue_t::reverse_iterator i = m_queue.rbegin();
			typename queue_t::reverse_iterator j(i);
			for (++j; j != m_queue.rend(); ++j)
			{
				// if the peer's torrent is not the same one
				// continue looking for a peer from the same torrent
				if (j->peer->associated_torrent().lock() != t)
					continue;
				// if we found a peer from the same torrent that
				// is prioritized, there is no point looking
				// any further.
				if (!j->non_prioritized) break;

				using std::swap;
				swap(*i, *j);
				i = j;
			}
		}

		if (m_queue.size() == 1) hand_out_bandwidth();
	}

#ifndef NDEBUG
	void check_invariant() const
	{
		int current_quota = 0;
		for (typename history_t::const_iterator i
			= m_history.begin(), end(m_history.end()); i != end; ++i)
		{
			current_quota += i->amount;
		}

		assert(current_quota == m_current_quota);
	}
#endif

private:

	void add_history_entry(history_entry<PeerConnection, Torrent> const& e) throw()
	{
#ifndef NDEBUG
		try {
#endif
		INVARIANT_CHECK;
		m_history.push_front(e);
		m_current_quota += e.amount;
		// in case the size > 1 there is already a timer
		// active that will be invoked, no need to set one up
		if (m_history.size() > 1) return;

		m_history_timer.expires_at(e.expires_at);
		m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1));
#ifndef NDEBUG
		}
		catch (std::exception&) { assert(false); }
#endif
	}

	void on_history_expire(asio::error_code const& e) throw()
	{
#ifndef NDEBUG
		try {
#endif
		INVARIANT_CHECK;

		if (e) return;

		assert(!m_history.empty());

		ptime now(time_now());
		while (!m_history.empty() && m_history.back().expires_at <= now)
		{
			history_entry<PeerConnection, Torrent> e = m_history.back();
			m_history.pop_back();
			m_current_quota -= e.amount;
			assert(m_current_quota >= 0);
			intrusive_ptr<PeerConnection> c = e.peer;
			shared_ptr<Torrent> t = e.tor.lock();
			if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount);
			if (t) t->expire_bandwidth(m_channel, e.amount);
		}

		// now, wait for the next chunk to expire
		if (!m_history.empty())
		{
			m_history_timer.expires_at(m_history.back().expires_at);
			m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1));
		}

		// since some bandwidth just expired, it
		// means we can hand out more (in case there
		// are still consumers in line)
		if (!m_queue.empty()) hand_out_bandwidth();
#ifndef NDEBUG
		}
		catch (std::exception&)
		{
			assert(false);
		}
#endif
	}

	void hand_out_bandwidth() throw()
	{
#ifndef NDEBUG
		try {
#endif
		INVARIANT_CHECK;

		ptime now(time_now());

		mutex_t::scoped_lock l(m_mutex);
		int limit = m_limit;
		l.unlock();

		// available bandwidth to hand out
		int amount = limit - m_current_quota;

		while (!m_queue.empty() && amount > 0)
		{
			assert(amount == limit - m_current_quota);
			bw_queue_entry<PeerConnection> qe = m_queue.front();
			m_queue.pop_front();

			shared_ptr<Torrent> t = qe.peer->associated_torrent().lock();
			if (!t) continue;
			if (qe.peer->is_disconnecting())
			{
				t->expire_bandwidth(m_channel, qe.max_block_size);
				continue;
			}

			// at this point, max_assignable may actually be zero. Since
			// the bandwidth quota is subtracted once the data has been
			// sent. If the peer was added to the queue while the data was
			// still being sent, max_assignable may have been > 0 at that time.
			int max_assignable = (std::min)(
				qe.peer->max_assignable_bandwidth(m_channel)
				, t->max_assignable_bandwidth(m_channel));
			if (max_assignable == 0)
			{
				t->expire_bandwidth(m_channel, qe.max_block_size);
				continue;
			}

			// this is the limit of the block size. It depends on the throttle
			// so that it can be closer to optimal. Larger block sizes will give lower
			// granularity to the rate but will be more efficient. At high rates
			// the block sizes are bigger and at low rates, the granularity
			// is more important and block sizes are smaller

			// the minimum rate that can be given is the block size, so, the
			// block size must be smaller for lower rates. This is because
			// the history window is one second, and the block will be forgotten
			// after one second.
			int block_size = (std::min)(qe.max_block_size
				, (std::min)(qe.peer->bandwidth_throttle(m_channel)
				, m_limit / 10));

			if (block_size < min_bandwidth_block_size)
			{
				block_size = min_bandwidth_block_size;
			}
			else if (block_size > max_bandwidth_block_size)
			{
				if (m_limit == bandwidth_limit::inf)
				{
					block_size = max_bandwidth_block_size;
				}
				else
				{
					// try to make the block_size a divisor of
					// m_limit to make the distributions as fair
					// as possible
					// TODO: move this calculcation to where the limit
					// is changed
					block_size = m_limit
						/ (m_limit / max_bandwidth_block_size);
				}
				if (block_size > qe.max_block_size) block_size = qe.max_block_size;
			}

			if (amount < block_size / 2)
			{
				m_queue.push_front(qe);
				break;
			}

			// so, hand out max_assignable, but no more than
			// the available bandwidth (amount) and no more
			// than the max_bandwidth_block_size
			int hand_out_amount = (std::min)((std::min)(block_size, max_assignable)
				, amount);
			assert(hand_out_amount > 0);
			amount -= hand_out_amount;
			assert(hand_out_amount <= qe.max_block_size);
			t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size);
			qe.peer->assign_bandwidth(m_channel, hand_out_amount);
			add_history_entry(history_entry<PeerConnection, Torrent>(
				qe.peer, t, hand_out_amount, now + bw_window_size));
		}
#ifndef NDEBUG
		}
		catch (std::exception& e)
		{ assert(false); };
#endif
	}

	typedef boost::mutex mutex_t;
	mutable mutex_t m_mutex;

	// the io_service used for the timer
	io_service& m_ios;

	// the timer that is waiting for the entries
	// in the history queue to expire (slide out
	// of the history window)
	deadline_timer m_history_timer;

	// the rate limit (bytes per second)
	int m_limit;

	// the sum of all recently handed out bandwidth blocks
	int m_current_quota;

	// these are the consumers that want bandwidth
	typedef std::deque<bw_queue_entry<PeerConnection> > queue_t;
	queue_t m_queue;

	// these are the consumers that have received bandwidth
	// that will expire
	typedef std::deque<history_entry<PeerConnection, Torrent> > history_t;
	history_t m_history;

	// this is the channel within the consumers
	// that bandwidth is assigned to (upload or download)
	int m_channel;
};

}

#endif

<commit_msg>rate limiter fix<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED
#define TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED

#include "libtorrent/socket.hpp"
#include "libtorrent/invariant_check.hpp"

#include <boost/shared_ptr.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/integer_traits.hpp>
#include <boost/thread/mutex.hpp>
#include <deque>

using boost::weak_ptr;
using boost::shared_ptr;
using boost::intrusive_ptr;
using boost::bind;

namespace libtorrent {

// the maximum block of bandwidth quota to
// hand out is 33kB. The block size may
// be smaller on lower limits
enum
{
	max_bandwidth_block_size = 33000,
	min_bandwidth_block_size = 400
};

const time_duration bw_window_size = seconds(1);

template<class PeerConnection, class Torrent>
struct history_entry
{
	history_entry(intrusive_ptr<PeerConnection> p, weak_ptr<Torrent> t
		, int a, ptime exp)
		: expires_at(exp), amount(a), peer(p), tor(t) {}
	ptime expires_at;
	int amount;
	intrusive_ptr<PeerConnection> peer;
	weak_ptr<Torrent> tor;
};

template<class PeerConnection>
struct bw_queue_entry
{
	bw_queue_entry(boost::intrusive_ptr<PeerConnection> const& pe
		, int blk, bool no_prio)
		: peer(pe), max_block_size(blk), non_prioritized(no_prio) {}
	boost::intrusive_ptr<PeerConnection> peer;
	int max_block_size;
	bool non_prioritized;
};

// member of peer_connection
struct bandwidth_limit
{
	static const int inf = boost::integer_traits<int>::const_max;

	bandwidth_limit() throw()
		: m_quota_left(0)
		, m_local_limit(inf)
		, m_current_rate(0)
	{}

	void throttle(int limit) throw()
	{
		m_local_limit = limit;
	}

	int throttle() const throw()
	{
		return m_local_limit;
	}

	void assign(int amount) throw()
	{
		assert(amount > 0);
		m_current_rate += amount;
		m_quota_left += amount;
	}

	void use_quota(int amount) throw()
	{
		assert(amount <= m_quota_left);
		m_quota_left -= amount;
	}

	int quota_left() const throw()
	{
		return (std::max)(m_quota_left, 0);
	}

	void expire(int amount) throw()
	{
		assert(amount >= 0);
		m_current_rate -= amount;
	}

	int max_assignable() const throw()
	{
		if (m_local_limit == inf) return inf;
		if (m_local_limit <= m_current_rate) return 0;
		return m_local_limit - m_current_rate;
	}

private:

	// this is the amount of bandwidth we have
	// been assigned without using yet. i.e.
	// the bandwidth that we use up every time
	// we receive or send a message. Once this
	// hits zero, we need to request more
	// bandwidth from the torrent which
	// in turn will request bandwidth from
	// the bandwidth manager
	int m_quota_left;

	// the local limit is the number of bytes
	// per window size we are allowed to use.
	int m_local_limit;

	// the current rate is the number of
	// bytes we have been assigned within
	// the window size.
	int m_current_rate;
};

template<class T>
T clamp(T val, T ceiling, T floor) throw()
{
	assert(ceiling >= floor);
	if (val >= ceiling) return ceiling;
	else if (val <= floor) return floor;
	return val;
}

template<class PeerConnection, class Torrent>
struct bandwidth_manager
{
	bandwidth_manager(io_service& ios, int channel) throw()
		: m_ios(ios)
		, m_history_timer(m_ios)
		, m_limit(bandwidth_limit::inf)
		, m_current_quota(0)
		, m_channel(channel)
	{}

	void throttle(int limit) throw()
	{
		mutex_t::scoped_lock l(m_mutex);
		assert(limit >= 0);
		m_limit = limit;
	}

	int throttle() const throw()
	{
		mutex_t::scoped_lock l(m_mutex);
		return m_limit;
	}

	// non prioritized means that, if there's a line for bandwidth,
	// others will cut in front of the non-prioritized peers.
	// this is used by web seeds
	void request_bandwidth(intrusive_ptr<PeerConnection> peer
		, int blk
		, bool non_prioritized) throw()
	{
		INVARIANT_CHECK;
		assert(blk > 0);

		assert(!peer->ignore_bandwidth_limits());

		// make sure this peer isn't already in line
		// waiting for bandwidth
#ifndef NDEBUG
		for (typename queue_t::iterator i = m_queue.begin()
			, end(m_queue.end()); i != end; ++i)
		{
			assert(i->peer < peer || peer < i->peer);
		}
#endif

		assert(peer->max_assignable_bandwidth(m_channel) > 0);
		boost::shared_ptr<Torrent> t = peer->associated_torrent().lock();
		m_queue.push_back(bw_queue_entry<PeerConnection>(peer, blk, non_prioritized));
		if (!non_prioritized)
		{
			typename queue_t::reverse_iterator i = m_queue.rbegin();
			typename queue_t::reverse_iterator j(i);
			for (++j; j != m_queue.rend(); ++j)
			{
				// if the peer's torrent is not the same one
				// continue looking for a peer from the same torrent
				if (j->peer->associated_torrent().lock() != t)
					continue;
				// if we found a peer from the same torrent that
				// is prioritized, there is no point looking
				// any further.
				if (!j->non_prioritized) break;

				using std::swap;
				swap(*i, *j);
				i = j;
			}
		}

		if (m_queue.size() == 1) hand_out_bandwidth();
	}

#ifndef NDEBUG
	void check_invariant() const
	{
		int current_quota = 0;
		for (typename history_t::const_iterator i
			= m_history.begin(), end(m_history.end()); i != end; ++i)
		{
			current_quota += i->amount;
		}

		assert(current_quota == m_current_quota);
	}
#endif

private:

	void add_history_entry(history_entry<PeerConnection, Torrent> const& e) throw()
	{
#ifndef NDEBUG
		try {
#endif
		INVARIANT_CHECK;
		m_history.push_front(e);
		m_current_quota += e.amount;
		// in case the size > 1 there is already a timer
		// active that will be invoked, no need to set one up
		if (m_history.size() > 1) return;

		m_history_timer.expires_at(e.expires_at);
		m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1));
#ifndef NDEBUG
		}
		catch (std::exception&) { assert(false); }
#endif
	}

	void on_history_expire(asio::error_code const& e) throw()
	{
#ifndef NDEBUG
		try {
#endif
		INVARIANT_CHECK;

		if (e) return;

		assert(!m_history.empty());

		ptime now(time_now());
		while (!m_history.empty() && m_history.back().expires_at <= now)
		{
			history_entry<PeerConnection, Torrent> e = m_history.back();
			m_history.pop_back();
			m_current_quota -= e.amount;
			assert(m_current_quota >= 0);
			intrusive_ptr<PeerConnection> c = e.peer;
			shared_ptr<Torrent> t = e.tor.lock();
			if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount);
			if (t) t->expire_bandwidth(m_channel, e.amount);
		}

		// now, wait for the next chunk to expire
		if (!m_history.empty())
		{
			m_history_timer.expires_at(m_history.back().expires_at);
			m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1));
		}

		// since some bandwidth just expired, it
		// means we can hand out more (in case there
		// are still consumers in line)
		if (!m_queue.empty()) hand_out_bandwidth();
#ifndef NDEBUG
		}
		catch (std::exception&)
		{
			assert(false);
		}
#endif
	}

	void hand_out_bandwidth() throw()
	{
#ifndef NDEBUG
		try {
#endif
		INVARIANT_CHECK;

		ptime now(time_now());

		mutex_t::scoped_lock l(m_mutex);
		int limit = m_limit;
		l.unlock();

		// available bandwidth to hand out
		int amount = limit - m_current_quota;

		while (!m_queue.empty() && amount > 0)
		{
			assert(amount == limit - m_current_quota);
			bw_queue_entry<PeerConnection> qe = m_queue.front();
			m_queue.pop_front();

			shared_ptr<Torrent> t = qe.peer->associated_torrent().lock();
			if (!t) continue;
			if (qe.peer->is_disconnecting())
			{
				t->expire_bandwidth(m_channel, qe.max_block_size);
				continue;
			}

			// at this point, max_assignable may actually be zero. Since
			// the bandwidth quota is subtracted once the data has been
			// sent. If the peer was added to the queue while the data was
			// still being sent, max_assignable may have been > 0 at that time.
			int max_assignable = (std::min)(
				qe.peer->max_assignable_bandwidth(m_channel)
				, t->max_assignable_bandwidth(m_channel));
			if (max_assignable == 0)
			{
				t->expire_bandwidth(m_channel, qe.max_block_size);
				continue;
			}

			// this is the limit of the block size. It depends on the throttle
			// so that it can be closer to optimal. Larger block sizes will give lower
			// granularity to the rate but will be more efficient. At high rates
			// the block sizes are bigger and at low rates, the granularity
			// is more important and block sizes are smaller

			// the minimum rate that can be given is the block size, so, the
			// block size must be smaller for lower rates. This is because
			// the history window is one second, and the block will be forgotten
			// after one second.
			int block_size = (std::min)(qe.peer->bandwidth_throttle(m_channel)
				, m_limit / 10);

			if (block_size < min_bandwidth_block_size)
			{
				block_size = min_bandwidth_block_size;
			}
			else if (block_size > max_bandwidth_block_size)
			{
				if (m_limit == bandwidth_limit::inf)
				{
					block_size = max_bandwidth_block_size;
				}
				else
				{
					// try to make the block_size a divisor of
					// m_limit to make the distributions as fair
					// as possible
					// TODO: move this calculcation to where the limit
					// is changed
					block_size = m_limit
						/ (m_limit / max_bandwidth_block_size);
				}
			}
			if (block_size > qe.max_block_size) block_size = qe.max_block_size;

			if (amount < block_size / 2)
			{
				m_queue.push_front(qe);
				break;
			}

			// so, hand out max_assignable, but no more than
			// the available bandwidth (amount) and no more
			// than the max_bandwidth_block_size
			int hand_out_amount = (std::min)((std::min)(block_size, max_assignable)
				, amount);
			assert(hand_out_amount > 0);
			amount -= hand_out_amount;
			assert(hand_out_amount <= qe.max_block_size);
			t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size);
			qe.peer->assign_bandwidth(m_channel, hand_out_amount);
			add_history_entry(history_entry<PeerConnection, Torrent>(
				qe.peer, t, hand_out_amount, now + bw_window_size));
		}
#ifndef NDEBUG
		}
		catch (std::exception& e)
		{ assert(false); };
#endif
	}

	typedef boost::mutex mutex_t;
	mutable mutex_t m_mutex;

	// the io_service used for the timer
	io_service& m_ios;

	// the timer that is waiting for the entries
	// in the history queue to expire (slide out
	// of the history window)
	deadline_timer m_history_timer;

	// the rate limit (bytes per second)
	int m_limit;

	// the sum of all recently handed out bandwidth blocks
	int m_current_quota;

	// these are the consumers that want bandwidth
	typedef std::deque<bw_queue_entry<PeerConnection> > queue_t;
	queue_t m_queue;

	// these are the consumers that have received bandwidth
	// that will expire
	typedef std::deque<history_entry<PeerConnection, Torrent> > history_t;
	history_t m_history;

	// this is the channel within the consumers
	// that bandwidth is assigned to (upload or download)
	int m_channel;
};

}

#endif

<|endoftext|>


<commit_before>inline bool Renderer::isInstanceLayerLoaded(const char* name) const {
    auto compareLayers = [&name](const char* layerName) {
        return std::strcmp(layerName, name) == 0;
    };

    return std::find_if(_loadedInstanceLayers.cbegin(), _loadedInstanceLayers.cend(), compareLayers) != _loadedInstanceLayers.cend();
}

inline bool Renderer::isInstanceExtensionLoaded(const char* name) const {
    auto compareExtensions = [&name](const char* extensionName) {
        return std::strcmp(extensionName, name) == 0;
    };

    return std::find_if(_loadedInstanceExtensions.cbegin(), _loadedInstanceExtensions.cend(), compareExtensions) != _loadedInstanceExtensions.cend();
}

inline bool Renderer::isDeviceExtensionLoaded(const char* name) const {
    auto compareExtensions = [&name](const char* extensionName) {
        return std::strcmp(extensionName, name) == 0;
    };

    return std::find_if(_loadedDeviceExtensions.cbegin(), _loadedDeviceExtensions.cend(), compareExtensions) != _loadedDeviceExtensions.cend();
}

inline const API::Instance& Renderer::getInstance() const {
    return _instance;
}

inline const API::Device& Renderer::getDevice() const {
    return _device;
}

inline std::vector<API::Queue> &Renderer::getQueues() {
    return _queues;
}

inline const std::vector<API::Queue>& Renderer::getQueues() const {
    return _queues;
}

inline API::Queue* Renderer::getQueue(VkQueueFlags flags, bool supportPresentation) {
    API::Queue* returnQueue = nullptr;

    for (auto& queue : _queues) {
        if ((queue.getFlags() & flags) == flags && (!supportPresentation || queue.supportsPresentation())) {
            if (returnQueue == nullptr || queue.getFlags() == flags || (supportPresentation && flags == 0 && queue.getFlags() & VK_QUEUE_GRAPHICS_BIT)) {
                returnQueue = &queue;
            }
        }
    }

    if (!returnQueue || flags == VK_QUEUE_TRANSFER_BIT) {
        return getQueue(VK_QUEUE_GRAPHICS_BIT, supportPresentation);
    }

    return returnQueue;
}

inline const API::Queue* Renderer::getQueue(VkQueueFlags flags, bool supportPresentation) const {
    const API::Queue* returnQueue = nullptr;

    for (const auto& queue : _queues) {
        if ((queue.getFlags() & flags) == flags && (!supportPresentation || queue.supportsPresentation())) {
            if (returnQueue == nullptr || queue.getFlags() == flags || (supportPresentation && flags == 0 && queue.getFlags() & VK_QUEUE_GRAPHICS_BIT)) {
                returnQueue = &queue;
            }
        }
    }

    if (!returnQueue || flags == VK_QUEUE_TRANSFER_BIT) {
        return getQueue(VK_QUEUE_GRAPHICS_BIT, supportPresentation);
    }

    return returnQueue;
}

inline bool Renderer::isSameQueue(VkQueueFlags flagsA, bool supportPresentationA, VkQueueFlags flagsB, bool supportPresentationB) const {
    return getQueue(flagsA, supportPresentationA) == getQueue(flagsB, supportPresentationB);
}

inline InstanceInfo& Renderer::getInstanceInfo() {
    return _instanceInfo;
}

inline const InstanceInfo& Renderer::getInstanceInfo() const {
    return _instanceInfo;
}

inline PhysicalDeviceInfo* Renderer::getPhysicalDeviceInfo() {
    return _physicalDeviceInfo;
}

inline const PhysicalDeviceInfo* Renderer::getPhysicalDeviceInfo() const {
    return _physicalDeviceInfo;
}

inline std::vector<PhysicalDeviceInfo>& Renderer::getPhysicalDeviceInfos() {
    return _physicalDeviceInfos;
}

inline const std::vector<PhysicalDeviceInfo>& Renderer::getPhysicalDeviceInfos() const {
    return _physicalDeviceInfos;
}

inline Renderer::Preferencies& Renderer::getPreferencies() {
    return _preferencies;
}

inline const Renderer::Preferencies& Renderer::getPreferencies() const {
    return _preferencies;
}
<commit_msg>Fix a bug for the function Renderer::getQueue()<commit_after>inline bool Renderer::isInstanceLayerLoaded(const char* name) const {
    auto compareLayers = [&name](const char* layerName) {
        return std::strcmp(layerName, name) == 0;
    };

    return std::find_if(_loadedInstanceLayers.cbegin(), _loadedInstanceLayers.cend(), compareLayers) != _loadedInstanceLayers.cend();
}

inline bool Renderer::isInstanceExtensionLoaded(const char* name) const {
    auto compareExtensions = [&name](const char* extensionName) {
        return std::strcmp(extensionName, name) == 0;
    };

    return std::find_if(_loadedInstanceExtensions.cbegin(), _loadedInstanceExtensions.cend(), compareExtensions) != _loadedInstanceExtensions.cend();
}

inline bool Renderer::isDeviceExtensionLoaded(const char* name) const {
    auto compareExtensions = [&name](const char* extensionName) {
        return std::strcmp(extensionName, name) == 0;
    };

    return std::find_if(_loadedDeviceExtensions.cbegin(), _loadedDeviceExtensions.cend(), compareExtensions) != _loadedDeviceExtensions.cend();
}

inline const API::Instance& Renderer::getInstance() const {
    return _instance;
}

inline const API::Device& Renderer::getDevice() const {
    return _device;
}

inline std::vector<API::Queue> &Renderer::getQueues() {
    return _queues;
}

inline const std::vector<API::Queue>& Renderer::getQueues() const {
    return _queues;
}

inline API::Queue* Renderer::getQueue(VkQueueFlags flags, bool supportPresentation) {
    API::Queue* returnQueue = nullptr;

    for (auto& queue : _queues) {
        if ((queue.getFlags() & flags) == flags && (!supportPresentation || queue.supportsPresentation())) {
            if (returnQueue == nullptr || queue.getFlags() == flags || (supportPresentation && flags == 0 && queue.getFlags() & VK_QUEUE_GRAPHICS_BIT)) {
                returnQueue = &queue;
            }
        }
    }

    if (!returnQueue && flags & VK_QUEUE_TRANSFER_BIT) {
        return getQueue((flags & ~VK_QUEUE_TRANSFER_BIT) | VK_QUEUE_GRAPHICS_BIT, supportPresentation);
    }

    return returnQueue;
}

inline const API::Queue* Renderer::getQueue(VkQueueFlags flags, bool supportPresentation) const {
    const API::Queue* returnQueue = nullptr;

    for (const auto& queue : _queues) {
        if ((queue.getFlags() & flags) == flags && (!supportPresentation || queue.supportsPresentation())) {
            if (returnQueue == nullptr || queue.getFlags() == flags || (supportPresentation && flags == 0 && queue.getFlags() & VK_QUEUE_GRAPHICS_BIT)) {
                returnQueue = &queue;
            }
        }
    }

    if (!returnQueue && flags & VK_QUEUE_TRANSFER_BIT) {
        return getQueue((flags & ~VK_QUEUE_TRANSFER_BIT) | VK_QUEUE_GRAPHICS_BIT, supportPresentation);
    }

    return returnQueue;
}

inline bool Renderer::isSameQueue(VkQueueFlags flagsA, bool supportPresentationA, VkQueueFlags flagsB, bool supportPresentationB) const {
    return getQueue(flagsA, supportPresentationA) == getQueue(flagsB, supportPresentationB);
}

inline InstanceInfo& Renderer::getInstanceInfo() {
    return _instanceInfo;
}

inline const InstanceInfo& Renderer::getInstanceInfo() const {
    return _instanceInfo;
}

inline PhysicalDeviceInfo* Renderer::getPhysicalDeviceInfo() {
    return _physicalDeviceInfo;
}

inline const PhysicalDeviceInfo* Renderer::getPhysicalDeviceInfo() const {
    return _physicalDeviceInfo;
}

inline std::vector<PhysicalDeviceInfo>& Renderer::getPhysicalDeviceInfos() {
    return _physicalDeviceInfos;
}

inline const std::vector<PhysicalDeviceInfo>& Renderer::getPhysicalDeviceInfos() const {
    return _physicalDeviceInfos;
}

inline Renderer::Preferencies& Renderer::getPreferencies() {
    return _preferencies;
}

inline const Renderer::Preferencies& Renderer::getPreferencies() const {
    return _preferencies;
}
<|endoftext|>


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

#ifndef RJ_GAME_EDITOR_EDITOR_HPP
#define RJ_GAME_EDITOR_EDITOR_HPP

#include "background_editor.hpp"
#include "editor_entity.hpp"
#include "itembar.hpp"
#include "mouse.hpp"
#include "settingsbar.hpp"
#include <rectojump/game/components/platform.hpp>
#include <rectojump/game/camera.hpp>
#include <rectojump/game/popup_manager.hpp>
#include <rectojump/game/world.hpp>

namespace rj
{
	template<typename Game_Handler, typename Game>
	class editor
	{
	public:
		using gh_type = Game_Handler;

	private:
		Game_Handler& m_gamehandler;
		Game& m_game;
		world<Game_Handler>& m_gameworld;
		entity_handler& m_entityhandler;
		level_manager& m_levelmgr;

		camera m_editarea_camera;
		camera m_itembar_camera;
		camera m_settingsbar_camera;

		editor_mouse<Game_Handler> m_mouse;
		background_editor<editor> m_background{*this};
		itembar<Game_Handler> m_itembar;
		settingsbar<editor> m_settingsbar;

	public:
		editor(Game_Handler& gh) :
			m_gamehandler{gh},
			m_game{gh.get_game()},
			m_gameworld{m_game.get_world()},
			m_entityhandler{m_gameworld.get_entityhandler()},
			m_levelmgr{gh.get_levelmgr()},
			m_editarea_camera{m_gamehandler.get_gamewindow()},
			m_itembar_camera{m_gamehandler.get_gamewindow()},
			m_settingsbar_camera{m_gamehandler.get_gamewindow()},
			m_mouse{gh},
			m_itembar{gh, {settings::get_window_size<vec2f>().x, 100.f}},
			m_settingsbar{*this, {300.f, settings::get_window_size<vec2f>().y - m_itembar.get_size().y}}
		{this->init();}

		void update(dur duration)
		{
			// edit area
			m_editarea_camera.activate();
			m_mouse.update(duration);

			// itembar
			m_itembar_camera.activate();
			m_itembar.update(duration);

			// settingsbar
			m_settingsbar_camera.activate();
			m_settingsbar.update(duration);
		}

		void update_input()
		{
			m_settingsbar.update_input();
		}

		void render()
		{
			// edit area
			m_editarea_camera.activate();
			m_entityhandler.render();
			m_mouse.render();

			// itembar
			m_itembar_camera.activate();
			m_itembar.render();

			// settingsbar
			m_settingsbar_camera.activate();
			m_settingsbar.render();
		}

		void on_activate()
		{
			m_background.reset();
		}

		void handle_save(const level_id& level_name)
		{
			if(!this->check_level_name(level_name))
				return;

			level_data lv_data;
			for(auto& a : m_entityhandler)
			{
				auto ent(this->to_editor_entity(a));
				lv_data.add_entity(ent->get_figure(), entity_propertie::solid, ent->pos());

			}

			level_info lv_info{level_name, "Creator", "Date"};
			music_data lv_music{'M', 'U', 'S', 'I', 'C'};
			level_packer<packer_mode::pack> lv_packer{lv_music, lv_data, lv_info};

			m_levelmgr.save_level(lv_packer, level_name);
		}

		void handle_load(const level_id& level_name)
		{
			if(!this->check_level_name(level_name))
				return;

//			auto& lv(m_levelmgr.get_level(level_name));
//			m_gameworld.load_level(lv.entities);
		}

		auto get_gamehandler() noexcept
		-> decltype(m_gamehandler)&
		{return m_gamehandler;}

	private:
		void init()
		{
			// change mousetexture on itembar-item click
			m_itembar.on_item_click =
			[this](ui::base_btn_ptr& b)
			{
				m_mouse.set_texture(b->get_texture());
				m_mouse.deactivate_selection();
				m_mouse.set_mouse_visible(true);
			};

			// init mouse texture
			m_itembar.deselect_all();

			this->init_input();
			this->init_cameras();
		}

		void init_input()
		{
			m_gamehandler.template add_input<state::editor>(
			[this](const vec2f& pos){this->on_mouse_left(pos);}, btn::Left);

			m_gamehandler.template add_input<state::editor>(
			[this](const vec2f& pos){this->on_mouse_right(pos);}, btn::Right);

			m_gamehandler.template add_input<state::editor>(
			[this](const vec2f& pos)
			{m_editarea_camera.move({settings::get_editor_scroll_step(), 0.f});}, wheel::down);

			m_gamehandler.template add_input<state::editor>(
			[this](const vec2f& pos)
			{
				if(m_editarea_camera.get_center().x >= m_editarea_camera.get_startcenter().x)
					m_editarea_camera.move({-settings::get_editor_scroll_step(), 0.f});
			}, wheel::up);
		}

		void init_cameras() noexcept
		{
			auto window_size(settings::get_window_size<vec2f>());
			auto& itembar_size(m_itembar.get_size());
			auto& settingsbar_size(m_settingsbar.get_size());

			auto itembar_top((window_size.y - itembar_size.y) / window_size.y);
			auto itembar_height(itembar_size.y / window_size.y);
			auto editarea_height((window_size.y - itembar_size.y) / window_size.y);

			sf::View editarea_view{vec2f{window_size.x, window_size.y - itembar_size.y} / 2.f, {window_size.x, window_size.y - itembar_size.y}};
			editarea_view.setViewport({0.f, 0.f, 1.f ,editarea_height});
			m_editarea_camera.set_view(editarea_view);

			sf::View itembar_view{vec2f{window_size.x, itembar_size.y} / 2.f, {window_size.x, itembar_size.y}};
			itembar_view.setViewport({0.f, itembar_top, 1.f, itembar_height});
			m_itembar_camera.set_view(itembar_view);

			sf::View settingsbar_view{vec2f{settingsbar_size.x, window_size.y} / 2.f, {settingsbar_size.x, window_size.y}};
			settingsbar_view.setViewport({(window_size.x - settingsbar_size.x) / window_size.x, 0.f, settingsbar_size.x / window_size.x, 1.f});
			m_settingsbar_camera.set_view(settingsbar_view);
		}

		void on_mouse_left(const vec2f&)
		{
			// check the itembar and settingsbar bounds
			auto itembar_mouse_bounds(bounds_from_vec(m_itembar_camera.get_mapped_mousepos()));
			auto settingsbar_mouse_bounds(bounds_from_vec(m_settingsbar_camera.get_mapped_mousepos()));
			if(itembar_mouse_bounds.intersects(m_itembar.get_bounds()) ||
			   settingsbar_mouse_bounds.intersects(m_settingsbar.get_bounds()))
				return;

			m_editarea_camera.activate();

			if(m_mouse.is_selection_visible())
			{
				if(m_mouse.get_selected().size() == 0)
					m_mouse.deactivate_selection();

				for(auto& a : m_mouse.get_selected())
				{
					auto new_ent(m_gameworld.template create_entity<editor_entity>(a.pos()));
					new_ent->set_texture(a.get_render_object().getTexture());
					new_ent->set_figure(a.get_figure());
				}
			}
			else if(m_mouse.is_mouse_visible())
			{
				float f{48.f};
				vec2f new_pos{round_to(m_editarea_camera.get_mapped_mousepos().x, f), round_to(m_editarea_camera.get_mapped_mousepos().y, f)};

				// set entity at pos
				if(m_mouse.get_texture())
				{
					auto ptr(m_gameworld.template create_entity<editor_entity>(new_pos));
					ptr->render_object().setTexture(m_mouse.get_texture());
					ptr->set_figure(m_itembar.get_current_figure());
				}
			}
			else
				m_mouse.selection_start();
		}

		void on_mouse_right(const vec2f&)
		{
			m_itembar.deselect_all();
			m_mouse.clear();

			auto iter(m_entityhandler.exists_entity_at(m_editarea_camera.get_mapped_mousepos()));
			if(iter != std::end(m_entityhandler))
				m_entityhandler.delete_entity(iter);
		}

		template<typename Ent_Ptr>
		auto to_editor_entity(const Ent_Ptr& ptr)
		-> decltype(std::static_pointer_cast<editor_entity>(ptr))
		{return std::static_pointer_cast<editor_entity>(ptr);}

		bool check_level_name(const level_id& id) const noexcept
		{
			if(!id.empty())
				return true;
			m_gamehandler.get_popupmgr().template create_popup<popup_type::error>("Couldn't save level: " + mlk::lerr_i().error_str(errors::lv_bad_name));
			return false;
		}
	};
}

#endif // RJ_GAME_EDITOR_EDITOR_HPP
<commit_msg>editor: fixed creating entity if there is already one set at the same position<commit_after>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_GAME_EDITOR_EDITOR_HPP
#define RJ_GAME_EDITOR_EDITOR_HPP

#include "background_editor.hpp"
#include "editor_entity.hpp"
#include "itembar.hpp"
#include "mouse.hpp"
#include "settingsbar.hpp"
#include <rectojump/game/components/platform.hpp>
#include <rectojump/game/camera.hpp>
#include <rectojump/game/popup_manager.hpp>
#include <rectojump/game/world.hpp>

namespace rj
{
	template<typename Game_Handler, typename Game>
	class editor
	{
	public:
		using gh_type = Game_Handler;

	private:
		Game_Handler& m_gamehandler;
		Game& m_game;
		world<Game_Handler>& m_gameworld;
		entity_handler& m_entityhandler;
		level_manager& m_levelmgr;

		camera m_editarea_camera;
		camera m_itembar_camera;
		camera m_settingsbar_camera;

		editor_mouse<Game_Handler> m_mouse;
		background_editor<editor> m_background{*this};
		itembar<Game_Handler> m_itembar;
		settingsbar<editor> m_settingsbar;

	public:
		editor(Game_Handler& gh) :
			m_gamehandler{gh},
			m_game{gh.get_game()},
			m_gameworld{m_game.get_world()},
			m_entityhandler{m_gameworld.get_entityhandler()},
			m_levelmgr{gh.get_levelmgr()},
			m_editarea_camera{m_gamehandler.get_gamewindow()},
			m_itembar_camera{m_gamehandler.get_gamewindow()},
			m_settingsbar_camera{m_gamehandler.get_gamewindow()},
			m_mouse{gh},
			m_itembar{gh, {settings::get_window_size<vec2f>().x, 100.f}},
			m_settingsbar{*this, {300.f, settings::get_window_size<vec2f>().y - m_itembar.get_size().y}}
		{this->init();}

		void update(dur duration)
		{
			// edit area
			m_editarea_camera.activate();
			m_mouse.update(duration);

			// itembar
			m_itembar_camera.activate();
			m_itembar.update(duration);

			// settingsbar
			m_settingsbar_camera.activate();
			m_settingsbar.update(duration);
		}

		void update_input()
		{
			m_settingsbar.update_input();
		}

		void render()
		{
			// edit area
			m_editarea_camera.activate();
			m_entityhandler.render();
			m_mouse.render();

			// itembar
			m_itembar_camera.activate();
			m_itembar.render();

			// settingsbar
			m_settingsbar_camera.activate();
			m_settingsbar.render();
		}

		void on_activate()
		{
			m_background.reset();
		}

		void handle_save(const level_id& level_name)
		{
			if(!this->check_level_name(level_name))
				return;

			level_data lv_data;
			for(auto& a : m_entityhandler)
			{
				auto ent(this->to_editor_entity(a));
				lv_data.add_entity(ent->get_figure(), entity_propertie::solid, ent->pos());

			}

			level_info lv_info{level_name, "Creator", "Date"};
			music_data lv_music{'M', 'U', 'S', 'I', 'C'};
			level_packer<packer_mode::pack> lv_packer{lv_music, lv_data, lv_info};

			m_levelmgr.save_level(lv_packer, level_name);
		}

		void handle_load(const level_id& level_name)
		{
			if(!this->check_level_name(level_name))
				return;

//			auto& lv(m_levelmgr.get_level(level_name));
//			m_gameworld.load_level(lv.entities);
		}

		auto get_gamehandler() noexcept
		-> decltype(m_gamehandler)&
		{return m_gamehandler;}

	private:
		void init()
		{
			// change mousetexture on itembar-item click
			m_itembar.on_item_click =
			[this](ui::base_btn_ptr& b)
			{
				m_mouse.set_texture(b->get_texture());
				m_mouse.deactivate_selection();
				m_mouse.set_mouse_visible(true);
			};

			// init mouse texture
			m_itembar.deselect_all();

			this->init_input();
			this->init_cameras();
		}

		void init_input()
		{
			m_gamehandler.template add_input<state::editor>(
			[this](const vec2f& pos){this->on_mouse_left(pos);}, btn::Left);

			m_gamehandler.template add_input<state::editor>(
			[this](const vec2f& pos){this->on_mouse_right(pos);}, btn::Right);

			m_gamehandler.template add_input<state::editor>(
			[this](const vec2f& pos)
			{m_editarea_camera.move({settings::get_editor_scroll_step(), 0.f});}, wheel::down);

			m_gamehandler.template add_input<state::editor>(
			[this](const vec2f& pos)
			{
				if(m_editarea_camera.get_center().x >= m_editarea_camera.get_startcenter().x)
					m_editarea_camera.move({-settings::get_editor_scroll_step(), 0.f});
			}, wheel::up);
		}

		void init_cameras() noexcept
		{
			auto window_size(settings::get_window_size<vec2f>());
			auto& itembar_size(m_itembar.get_size());
			auto& settingsbar_size(m_settingsbar.get_size());

			auto itembar_top((window_size.y - itembar_size.y) / window_size.y);
			auto itembar_height(itembar_size.y / window_size.y);
			auto editarea_height((window_size.y - itembar_size.y) / window_size.y);

			sf::View editarea_view{vec2f{window_size.x, window_size.y - itembar_size.y} / 2.f, {window_size.x, window_size.y - itembar_size.y}};
			editarea_view.setViewport({0.f, 0.f, 1.f ,editarea_height});
			m_editarea_camera.set_view(editarea_view);

			sf::View itembar_view{vec2f{window_size.x, itembar_size.y} / 2.f, {window_size.x, itembar_size.y}};
			itembar_view.setViewport({0.f, itembar_top, 1.f, itembar_height});
			m_itembar_camera.set_view(itembar_view);

			sf::View settingsbar_view{vec2f{settingsbar_size.x, window_size.y} / 2.f, {settingsbar_size.x, window_size.y}};
			settingsbar_view.setViewport({(window_size.x - settingsbar_size.x) / window_size.x, 0.f, settingsbar_size.x / window_size.x, 1.f});
			m_settingsbar_camera.set_view(settingsbar_view);
		}

		void on_mouse_left(const vec2f&)
		{
			// check the itembar and settingsbar bounds
			auto itembar_mouse_bounds(bounds_from_vec(m_itembar_camera.get_mapped_mousepos()));
			auto settingsbar_mouse_bounds(bounds_from_vec(m_settingsbar_camera.get_mapped_mousepos()));
			if(itembar_mouse_bounds.intersects(m_itembar.get_bounds()) ||
			   settingsbar_mouse_bounds.intersects(m_settingsbar.get_bounds()))
				return;

			m_editarea_camera.activate();

			if(m_mouse.is_selection_visible())
			{
				if(m_mouse.get_selected().size() == 0)
					m_mouse.deactivate_selection();

				for(auto& a : m_mouse.get_selected())
				{
					if(m_gameworld.get_entityhandler().exists_entity_at(a.pos()))
						continue;
					auto new_ent(m_gameworld.template create_entity<editor_entity>(a.pos()));
					new_ent->set_texture(a.get_render_object().getTexture());
					new_ent->set_figure(a.get_figure());
				}
			}
			else if(m_mouse.is_mouse_visible())
			{
				float f{48.f};
				vec2f new_pos{round_to(m_editarea_camera.get_mapped_mousepos().x, f), round_to(m_editarea_camera.get_mapped_mousepos().y, f)};

				// set entity at pos
				if(m_mouse.get_texture() && !m_gameworld.get_entityhandler().exists_entity_at(new_pos))
				{
					auto ptr(m_gameworld.template create_entity<editor_entity>(new_pos));
					ptr->render_object().setTexture(m_mouse.get_texture());
					ptr->set_figure(m_itembar.get_current_figure());
				}
			}
			else
				m_mouse.selection_start();
		}

		void on_mouse_right(const vec2f&)
		{
			m_itembar.deselect_all();
			m_mouse.clear();

			auto iter(m_entityhandler.get_entity_at(m_editarea_camera.get_mapped_mousepos()));
			if(iter != std::end(m_entityhandler))
				m_entityhandler.delete_entity(iter);
		}

		template<typename Ent_Ptr>
		auto to_editor_entity(const Ent_Ptr& ptr)
		-> decltype(std::static_pointer_cast<editor_entity>(ptr))
		{return std::static_pointer_cast<editor_entity>(ptr);}

		bool check_level_name(const level_id& id) const noexcept
		{
			if(!id.empty())
				return true;
			m_gamehandler.get_popupmgr().template create_popup<popup_type::error>("Couldn't save level: " + mlk::lerr_i().error_str(errors::lv_bad_name));
			return false;
		}
	};
}

#endif // RJ_GAME_EDITOR_EDITOR_HPP
<|endoftext|>