<commit_before>// Copyright (c) 2014, Salesforce.com, Inc.  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 Salesforce.com 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 HOLDER 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.

#pragma once

#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <limits>
#include <distributions/common.hpp>
#include <distributions/vendor/fmath.hpp>

#define M_PIf (3.14159265358979f)

namespace distributions
{

template<class T> T sqr (const T & t)
{
    return t * t;
}

//----------------------------------------------------------------------------
// fast_log, fast_exp, fast_log_sum_exp, log_sum_exp

namespace detail
{

/// Implements the ICSI fast log algorithm, v2.
class FastLog
{
public:

    FastLog (int N);

    inline float log (float x)
    {
        //int intx = * reinterpret_cast<int *>(& x);
        int intx;
        memcpy(&intx, &x, 4);

        register const int exp = ((intx >> 23) & 255) - 127;
        register const int man = (intx & 0x7FFFFF) >> (23 - N_);

        // exponent plus lookup refinement
        return ((float)(exp) + table_[man]) * 0.69314718055994529f;
    }

private:

    const int N_;
    std::vector<float> table_;
};

static FastLog GLOBAL_FAST_LOG_14(14);

} // namespace detail

inline float eric_log (float x)
{
    return detail::GLOBAL_FAST_LOG_14.log(x);
}

inline float fast_log (float x)
{
    return eric_log(x);
    //return fmath::log(x);
}

inline float fast_exp (float x)
{
    return fmath::exp(x);
}

inline float fast_log_sum_exp (float x, float y)
{
    float min = x < y ? x : y;
    float max = x < y ? y : x;

    return max + fast_log(1.0f + fast_exp(min - max));
}

inline float log_sum_exp (float x, float y)
{
    float min = x < y ? x : y;
    float max = x < y ? y : x;
    return max + logf(1.0f + expf(min - max));
}

//----------------------------------------------------------------------------
// fast_lgamma, fast_log_beta, log_beta, log_binom, fast_log_binom

namespace detail
{

extern const char LogTable256[256];
extern const float lgamma_approx_coeff5[];

} // namespace detail

inline float fast_lgamma (float y)
{
    // A piecewise fifth-order approximation of loggamma,
    // which bottoms out in libc gammaln for vals < 1.0
    // and throws an exception outside of the domain 2**32
    //
    // see loggamma.py for the code used to generate the coefficient table

    if (DIST_UNLIKELY(y < 2.5f or 4294967295.0f <= y)) {
        return lgammaf(y);
    }

    // adapted from:
    // http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
    float v = y;                // find int(log2(v)), where v > 0.0 && finite(v)
    int c;                      // 32-bit int c gets the result;
    int x = *(const int *) &v;  // or portably:  memcpy(&x, &v, sizeof x);

    c = x >> 23;

    if (c) {
        c -= 127;
    } else { // subnormal, so recompute using mantissa: c = intlog2(x) - 149;
        register unsigned int t; // temporary
        if ((t = x >> 16)) {
            c = detail::LogTable256[t] - 133;
        } else {
            c = (t = x >> 8)
              ? detail::LogTable256[t] - 141
              : detail::LogTable256[x] - 149;
        }
    }

    int pos = c *6;
    float a5 = detail::lgamma_approx_coeff5[pos];
    float a4 = detail::lgamma_approx_coeff5[pos + 1];
    float a3 = detail::lgamma_approx_coeff5[pos + 2];
    float a2 = detail::lgamma_approx_coeff5[pos + 3];
    float a1 = detail::lgamma_approx_coeff5[pos + 4];
    float a0 = detail::lgamma_approx_coeff5[pos + 5];

    double yprod = y;
    double sum = a0;
    sum += a1 * yprod;

    yprod *= y;
    sum += a2 * yprod;

    yprod *= y;
    sum += a3 * yprod;

    yprod *= y;
    sum += a4 * yprod;

    yprod *= y;
    sum += a5 * yprod;

    return sum;
}

inline float log_beta (float alpha, float beta)
{
    if (DIST_UNLIKELY(alpha <= 0.f or beta <= 0.f)) {
        return - std::numeric_limits<float>::infinity();
    } else {
        return lgamma(alpha) + lgamma(beta) - lgamma(alpha + beta);
    }
}

inline float fast_log_beta (float alpha, float beta)
{
    if (DIST_UNLIKELY(alpha <= 0.f or beta <= 0.f)) {
        return - std::numeric_limits<float>::infinity();
    } else {
        return fast_lgamma(alpha)
             + fast_lgamma(beta)
             - fast_lgamma(alpha + beta);
    }
}

inline float log_binom (float N, float k)
{
    return lgamma(N + 1) - (lgamma(k + 1) + lgamma(N - k + 1));
}

inline float fast_log_binom (float N, float k)
{
    return fast_lgamma(N + 1) - (fast_lgamma(k + 1) + fast_lgamma(N - k + 1));
}

//----------------------------------------------------------------------------
// fast_log_factorial

namespace detail
{

extern const float log_factorial_table[64];

} // namespace detail

inline float fast_log_factorial(const uint32_t & n)
{
    if (n < 64) {
        return detail::log_factorial_table[n];
    } else {
        return fast_lgamma(n + 1);
    }
}

//----------------------------------------------------------------------------
// fast_lgamma_nu

namespace detail
{

extern const float lgamma_nu_func_approx_coeff3[];

inline float poly_eval_3 (
        const float * __restrict__ coeff,
        float x)
{
    // evaluate the polynomial with the indicated
    // coefficients
    float a0 = coeff[3];
    float a1 = coeff[2];
    float a2 = coeff[1];
    float a3 = coeff[0];

    return a0 + x*a1 + x*x*a2 + x*x*x*a3;
}

} // namespace detail

inline float fast_lgamma_nu (float nu)
{
    // Approximation of the sensitive, time-consuming
    // lgamma(nu / 2.0 + 0.5) - lgamma(nu/2.0)
    // function inside log student t

    // see loggamma.py:lstudent for coeff gen

    if (DIST_UNLIKELY(nu < 0.0625f or 4294967295.0f <= nu)) {
        return lgammaf(nu * 0.5f + 0.5f) - lgammaf(nu * 0.5f);
    }

    // adapted from:
    // http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
    float v = nu;               // find int(log2(v)), where v > 0.0 && finite(v)
    int c;                      // 32-bit int c gets the result;
    int x = *(const int *) &v;  // or portably:  memcpy(&x, &v, sizeof x);

    c = x >> 23;

    if (c) {
        c -= 127;
    } else { // subnormal, so recompute using mantissa: c = intlog2(x) - 149;
        register unsigned int t; // temporary
        if ((t = x >> 16)) {
            c = detail::LogTable256[t] - 133;
        } else {
            c = (t = x >> 8)
              ? detail::LogTable256[t] - 141
              : detail::LogTable256[x] - 149;
        }
    }

    int pos = ((c + 4) / 2) * 4 ; // remember the POT range is 2
    return detail::poly_eval_3(detail::lgamma_nu_func_approx_coeff3 + pos, nu);
}

/**
 * http://en.wikipedia.org/wiki/Multivariate_gamma_function
 */
inline float lmultigamma(unsigned d, float a)
{
    DIST_ASSERT1(d > 0, "zero dim lmultigamma");
    const float term1 = 0.25*float(d*(d-1))*1.1447298858494002 /* log(pi) */;
    float term2 = 0.;
    for (int j = 1; j <= (int)d; j++)
        term2 += fast_lgamma(a + 0.5*float(1-j));
    return term1 + term2;
}

//----------------------------------------------------------------------------
// misc

// Compute stirling numbers of first kind S(n,k), one row at a time
// return [log(S(n,0), ..., log(S(n,n))]
// http://en.wikipedia.org/wiki/Stirling_numbers_of_the_first_kind
template<class Alloc>
void get_log_stirling1_row (size_t n, std::vector<float, Alloc> & result);

inline std::vector<float> log_stirling1_row (size_t n)
{
    std::vector<float> result;
    get_log_stirling1_row(n, result);
    return result;
}

} // namespace distributions
<commit_msg>missing style<commit_after>// Copyright (c) 2014, Salesforce.com, Inc.  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 Salesforce.com 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 HOLDER 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.

#pragma once

#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <limits>
#include <distributions/common.hpp>
#include <distributions/vendor/fmath.hpp>

#define M_PIf (3.14159265358979f)

namespace distributions
{

template<class T> T sqr (const T & t)
{
    return t * t;
}

//----------------------------------------------------------------------------
// fast_log, fast_exp, fast_log_sum_exp, log_sum_exp

namespace detail
{

/// Implements the ICSI fast log algorithm, v2.
class FastLog
{
public:

    FastLog (int N);

    inline float log (float x)
    {
        //int intx = * reinterpret_cast<int *>(& x);
        int intx;
        memcpy(&intx, &x, 4);

        register const int exp = ((intx >> 23) & 255) - 127;
        register const int man = (intx & 0x7FFFFF) >> (23 - N_);

        // exponent plus lookup refinement
        return ((float)(exp) + table_[man]) * 0.69314718055994529f;
    }

private:

    const int N_;
    std::vector<float> table_;
};

static FastLog GLOBAL_FAST_LOG_14(14);

} // namespace detail

inline float eric_log (float x)
{
    return detail::GLOBAL_FAST_LOG_14.log(x);
}

inline float fast_log (float x)
{
    return eric_log(x);
    //return fmath::log(x);
}

inline float fast_exp (float x)
{
    return fmath::exp(x);
}

inline float fast_log_sum_exp (float x, float y)
{
    float min = x < y ? x : y;
    float max = x < y ? y : x;

    return max + fast_log(1.0f + fast_exp(min - max));
}

inline float log_sum_exp (float x, float y)
{
    float min = x < y ? x : y;
    float max = x < y ? y : x;
    return max + logf(1.0f + expf(min - max));
}

//----------------------------------------------------------------------------
// fast_lgamma, fast_log_beta, log_beta, log_binom, fast_log_binom

namespace detail
{

extern const char LogTable256[256];
extern const float lgamma_approx_coeff5[];

} // namespace detail

inline float fast_lgamma (float y)
{
    // A piecewise fifth-order approximation of loggamma,
    // which bottoms out in libc gammaln for vals < 1.0
    // and throws an exception outside of the domain 2**32
    //
    // see loggamma.py for the code used to generate the coefficient table

    if (DIST_UNLIKELY(y < 2.5f or 4294967295.0f <= y)) {
        return lgammaf(y);
    }

    // adapted from:
    // http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
    float v = y;                // find int(log2(v)), where v > 0.0 && finite(v)
    int c;                      // 32-bit int c gets the result;
    int x = *(const int *) &v;  // or portably:  memcpy(&x, &v, sizeof x);

    c = x >> 23;

    if (c) {
        c -= 127;
    } else { // subnormal, so recompute using mantissa: c = intlog2(x) - 149;
        register unsigned int t; // temporary
        if ((t = x >> 16)) {
            c = detail::LogTable256[t] - 133;
        } else {
            c = (t = x >> 8)
              ? detail::LogTable256[t] - 141
              : detail::LogTable256[x] - 149;
        }
    }

    int pos = c *6;
    float a5 = detail::lgamma_approx_coeff5[pos];
    float a4 = detail::lgamma_approx_coeff5[pos + 1];
    float a3 = detail::lgamma_approx_coeff5[pos + 2];
    float a2 = detail::lgamma_approx_coeff5[pos + 3];
    float a1 = detail::lgamma_approx_coeff5[pos + 4];
    float a0 = detail::lgamma_approx_coeff5[pos + 5];

    double yprod = y;
    double sum = a0;
    sum += a1 * yprod;

    yprod *= y;
    sum += a2 * yprod;

    yprod *= y;
    sum += a3 * yprod;

    yprod *= y;
    sum += a4 * yprod;

    yprod *= y;
    sum += a5 * yprod;

    return sum;
}

inline float log_beta (float alpha, float beta)
{
    if (DIST_UNLIKELY(alpha <= 0.f or beta <= 0.f)) {
        return - std::numeric_limits<float>::infinity();
    } else {
        return lgamma(alpha) + lgamma(beta) - lgamma(alpha + beta);
    }
}

inline float fast_log_beta (float alpha, float beta)
{
    if (DIST_UNLIKELY(alpha <= 0.f or beta <= 0.f)) {
        return - std::numeric_limits<float>::infinity();
    } else {
        return fast_lgamma(alpha)
             + fast_lgamma(beta)
             - fast_lgamma(alpha + beta);
    }
}

inline float log_binom (float N, float k)
{
    return lgamma(N + 1) - (lgamma(k + 1) + lgamma(N - k + 1));
}

inline float fast_log_binom (float N, float k)
{
    return fast_lgamma(N + 1) - (fast_lgamma(k + 1) + fast_lgamma(N - k + 1));
}

//----------------------------------------------------------------------------
// fast_log_factorial

namespace detail
{

extern const float log_factorial_table[64];

} // namespace detail

inline float fast_log_factorial(const uint32_t & n)
{
    if (n < 64) {
        return detail::log_factorial_table[n];
    } else {
        return fast_lgamma(n + 1);
    }
}

//----------------------------------------------------------------------------
// fast_lgamma_nu

namespace detail
{

extern const float lgamma_nu_func_approx_coeff3[];

inline float poly_eval_3 (
        const float * __restrict__ coeff,
        float x)
{
    // evaluate the polynomial with the indicated
    // coefficients
    float a0 = coeff[3];
    float a1 = coeff[2];
    float a2 = coeff[1];
    float a3 = coeff[0];

    return a0 + x*a1 + x*x*a2 + x*x*x*a3;
}

} // namespace detail

inline float fast_lgamma_nu (float nu)
{
    // Approximation of the sensitive, time-consuming
    // lgamma(nu / 2.0 + 0.5) - lgamma(nu/2.0)
    // function inside log student t

    // see loggamma.py:lstudent for coeff gen

    if (DIST_UNLIKELY(nu < 0.0625f or 4294967295.0f <= nu)) {
        return lgammaf(nu * 0.5f + 0.5f) - lgammaf(nu * 0.5f);
    }

    // adapted from:
    // http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
    float v = nu;               // find int(log2(v)), where v > 0.0 && finite(v)
    int c;                      // 32-bit int c gets the result;
    int x = *(const int *) &v;  // or portably:  memcpy(&x, &v, sizeof x);

    c = x >> 23;

    if (c) {
        c -= 127;
    } else { // subnormal, so recompute using mantissa: c = intlog2(x) - 149;
        register unsigned int t; // temporary
        if ((t = x >> 16)) {
            c = detail::LogTable256[t] - 133;
        } else {
            c = (t = x >> 8)
              ? detail::LogTable256[t] - 141
              : detail::LogTable256[x] - 149;
        }
    }

    int pos = ((c + 4) / 2) * 4 ; // remember the POT range is 2
    return detail::poly_eval_3(detail::lgamma_nu_func_approx_coeff3 + pos, nu);
}

/**
 * http://en.wikipedia.org/wiki/Multivariate_gamma_function
 */
inline float lmultigamma(unsigned d, float a)
{
    DIST_ASSERT1(d > 0, "zero dim lmultigamma");
    const float log_pi = 1.1447298858494002;
    const float term1 = 0.25 * float(d * (d - 1)) * log_pi;
    float term2 = 0.;
    for (int j = 1; j <= (int)d; j++)
        term2 += fast_lgamma(a + 0.5 * float(1 - j));
    return term1 + term2;
}

//----------------------------------------------------------------------------
// misc

// Compute stirling numbers of first kind S(n,k), one row at a time
// return [log(S(n,0), ..., log(S(n,n))]
// http://en.wikipedia.org/wiki/Stirling_numbers_of_the_first_kind
template<class Alloc>
void get_log_stirling1_row (size_t n, std::vector<float, Alloc> & result);

inline std::vector<float> log_stirling1_row (size_t n)
{
    std::vector<float> result;
    get_log_stirling1_row(n, result);
    return result;
}

} // namespace distributions
<|endoftext|>


<commit_before>/*

Copyright (c) 2006-2012, 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_EXTENSIONS_HPP_INCLUDED
#define TORRENT_EXTENSIONS_HPP_INCLUDED

#ifndef TORRENT_DISABLE_EXTENSIONS

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/weak_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <vector>
#include "libtorrent/config.hpp"
#include "libtorrent/buffer.hpp"
#include "libtorrent/socket.hpp"

namespace libtorrent
{
	namespace aux { struct session_impl; }

	struct peer_plugin;
	class bt_peer_connection;
	struct peer_request;
	class peer_connection;
	class entry;
	struct lazy_entry;
	struct disk_buffer_holder;
	struct bitfield;
	class alert;
	struct torrent_plugin;
	class torrent;

	struct TORRENT_EXPORT plugin
	{
		virtual ~plugin() {}

		virtual boost::shared_ptr<torrent_plugin> new_torrent(torrent* t, void* user)
		{ return boost::shared_ptr<torrent_plugin>(); }

		// called when plugin is added to a session
		virtual void added(boost::weak_ptr<aux::session_impl> s) {}

		// called when an alert is posted
		// alerts that are filtered are not
		// posted
		virtual void on_alert(alert const* a) {}

		// called once per second
		virtual void on_tick() {}

		// called when saving settings state
		virtual void save_state(entry& ent) const {}

		// called when loading settings state
		virtual void load_state(lazy_entry const& ent) {}
	};

	struct TORRENT_EXPORT torrent_plugin
	{
		virtual ~torrent_plugin() {}
		// throwing an exception closes the connection
		// returning a 0 pointer is valid and will not add
		// the peer_plugin to the peer_connection
		virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection*)
		{ return boost::shared_ptr<peer_plugin>(); }

		virtual void on_piece_pass(int index) {}
		virtual void on_piece_failed(int index) {}

		// called aproximately once every second
		virtual void tick() {}

		// if true is returned, it means the handler handled the event,
		// and no other plugins will have their handlers called, and the
		// default behavior will be skipped
		virtual bool on_pause() { return false; }
		virtual bool on_resume() { return false; }

		// this is called when the initial checking of
		// files is completed.
		virtual void on_files_checked() {}

		// called when the torrent changes state
		// the state is one of torrent_status::state_t
		// enum members
		virtual void on_state(int s) {}

		// called every time policy::add_peer is called
		// src is a bitmask of which sources this peer
		// has been seen from. flags is a bitmask of:

		enum flags_t {
			// this is the first time we see this peer
			first_time = 1,
			// this peer was not added because it was
			// filtered by the IP filter
			filtered = 2
		};

		virtual void on_add_peer(tcp::endpoint const& ip
			, int src, int flags) {}
	};

	struct TORRENT_EXPORT peer_plugin
	{
		virtual ~peer_plugin() {}

		virtual char const* type() const { return ""; }

		// can add entries to the extension handshake
		// this is not called for web seeds
		virtual void add_handshake(entry&) {}

		// throwing an exception from any of the handlers (except add_handshake)
		// closes the connection

		// this is called when the initial BT handshake is received. Returning false
		// means that the other end doesn't support this extension and will remove
		// it from the list of plugins.
		// this is not called for web seeds
		virtual bool on_handshake(char const* reserved_bits) { return true; }

		// called when the extension handshake from the other end is received
		// if this returns false, it means that this extension isn't
		// supported by this peer. It will result in this peer_plugin
		// being removed from the peer_connection and destructed.
		// this is not called for web seeds
		virtual bool on_extension_handshake(lazy_entry const& h) { return true; }

		// returning true from any of the message handlers
		// indicates that the plugin has handeled the message.
		// it will break the plugin chain traversing and not let
		// anyone else handle the message, including the default
		// handler.

		virtual bool on_choke()
		{ return false; }

		virtual bool on_unchoke()
		{ return false; }

		virtual bool on_interested()
		{ return false; }

		virtual bool on_not_interested()
		{ return false; }

		virtual bool on_have(int index)
		{ return false; }

		virtual bool on_dont_have(int index)
		{ return false; }

		virtual bool on_bitfield(bitfield const& bitfield)
		{ return false; }

		virtual bool on_have_all()
		{ return false; }

		virtual bool on_have_none()
		{ return false; }

		virtual bool on_allowed_fast(int index)
		{ return false; }

		virtual bool on_request(peer_request const& req)
		{ return false; }

		virtual bool on_piece(peer_request const& piece, disk_buffer_holder& data)
		{ return false; }

		virtual bool on_cancel(peer_request const& req)
		{ return false; }

		virtual bool on_reject(peer_request const& req)
		{ return false; }

		virtual bool on_suggest(int index)
		{ return false; }

		// called when an extended message is received. If returning true,
		// the message is not processed by any other plugin and if false
		// is returned the next plugin in the chain will receive it to
		// be able to handle it
		// this is not called for web seeds
		virtual bool on_extended(int length
			, int msg, buffer::const_interval body)
		{ return false; }

		// this is not called for web seeds
		virtual bool on_unknown_message(int length, int msg
			, buffer::const_interval body)
		{ return false; }

		// called when a piece that this peer participated in either
		// fails or passes the hash_check
		virtual void on_piece_pass(int index) {}
		virtual void on_piece_failed(int index) {}

		// called aproximately once every second
		virtual void tick() {}

		// called each time a request message is to be sent. If true
		// is returned, the original request message won't be sent and
		// no other plugin will have this function called.
		virtual bool write_request(peer_request const& r) { return false; }
	};

}

#endif

#endif // TORRENT_EXTENSIONS_HPP_INCLUDED

<commit_msg>fix some unused variables warnings in extension.hpp<commit_after>/*

Copyright (c) 2006-2012, 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_EXTENSIONS_HPP_INCLUDED
#define TORRENT_EXTENSIONS_HPP_INCLUDED

#ifndef TORRENT_DISABLE_EXTENSIONS

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/weak_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <vector>
#include "libtorrent/config.hpp"
#include "libtorrent/buffer.hpp"
#include "libtorrent/socket.hpp"

namespace libtorrent
{
	namespace aux { struct session_impl; }

	struct peer_plugin;
	class bt_peer_connection;
	struct peer_request;
	class peer_connection;
	class entry;
	struct lazy_entry;
	struct disk_buffer_holder;
	struct bitfield;
	class alert;
	struct torrent_plugin;
	class torrent;

	struct TORRENT_EXPORT plugin
	{
		virtual ~plugin() {}

		virtual boost::shared_ptr<torrent_plugin> new_torrent(torrent*, void*)
		{ return boost::shared_ptr<torrent_plugin>(); }

		// called when plugin is added to a session
		virtual void added(boost::weak_ptr<aux::session_impl>) {}

		// called when an alert is posted
		// alerts that are filtered are not
		// posted
		virtual void on_alert(alert const*) {}

		// called once per second
		virtual void on_tick() {}

		// called when saving settings state
		virtual void save_state(entry&) const {}

		// called when loading settings state
		virtual void load_state(lazy_entry const&) {}
	};

	struct TORRENT_EXPORT torrent_plugin
	{
		virtual ~torrent_plugin() {}
		// throwing an exception closes the connection
		// returning a 0 pointer is valid and will not add
		// the peer_plugin to the peer_connection
		virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection*)
		{ return boost::shared_ptr<peer_plugin>(); }

		virtual void on_piece_pass(int /*index*/) {}
		virtual void on_piece_failed(int /*index*/) {}

		// called aproximately once every second
		virtual void tick() {}

		// if true is returned, it means the handler handled the event,
		// and no other plugins will have their handlers called, and the
		// default behavior will be skipped
		virtual bool on_pause() { return false; }
		virtual bool on_resume() { return false; }

		// this is called when the initial checking of
		// files is completed.
		virtual void on_files_checked() {}

		// called when the torrent changes state
		// the state is one of torrent_status::state_t
		// enum members
		virtual void on_state(int /*s*/) {}

		// called every time policy::add_peer is called
		// src is a bitmask of which sources this peer
		// has been seen from. flags is a bitmask of:

		enum flags_t {
			// this is the first time we see this peer
			first_time = 1,
			// this peer was not added because it was
			// filtered by the IP filter
			filtered = 2
		};

		virtual void on_add_peer(tcp::endpoint const&,
			int /*src*/, int /*flags*/) {}
	};

	struct TORRENT_EXPORT peer_plugin
	{
		virtual ~peer_plugin() {}

		virtual char const* type() const { return ""; }

		// can add entries to the extension handshake
		// this is not called for web seeds
		virtual void add_handshake(entry&) {}

		// throwing an exception from any of the handlers (except add_handshake)
		// closes the connection

		// this is called when the initial BT handshake is received. Returning false
		// means that the other end doesn't support this extension and will remove
		// it from the list of plugins.
		// this is not called for web seeds
		virtual bool on_handshake(char const* /*reserved_bits*/) { return true; }

		// called when the extension handshake from the other end is received
		// if this returns false, it means that this extension isn't
		// supported by this peer. It will result in this peer_plugin
		// being removed from the peer_connection and destructed.
		// this is not called for web seeds
		virtual bool on_extension_handshake(lazy_entry const&) { return true; }

		// returning true from any of the message handlers
		// indicates that the plugin has handeled the message.
		// it will break the plugin chain traversing and not let
		// anyone else handle the message, including the default
		// handler.

		virtual bool on_choke()
		{ return false; }

		virtual bool on_unchoke()
		{ return false; }

		virtual bool on_interested()
		{ return false; }

		virtual bool on_not_interested()
		{ return false; }

		virtual bool on_have(int /*index*/)
		{ return false; }

		virtual bool on_dont_have(int /*index*/)
		{ return false; }

		virtual bool on_bitfield(bitfield const& /*bitfield*/)
		{ return false; }

		virtual bool on_have_all()
		{ return false; }

		virtual bool on_have_none()
		{ return false; }

		virtual bool on_allowed_fast(int /*index*/)
		{ return false; }

		virtual bool on_request(peer_request const&)
		{ return false; }

		virtual bool on_piece(peer_request const& /*piece*/, disk_buffer_holder& /*data*/)
		{ return false; }

		virtual bool on_cancel(peer_request const&)
		{ return false; }

		virtual bool on_reject(peer_request const&)
		{ return false; }

		virtual bool on_suggest(int /*index*/)
		{ return false; }

		// called when an extended message is received. If returning true,
		// the message is not processed by any other plugin and if false
		// is returned the next plugin in the chain will receive it to
		// be able to handle it
		// this is not called for web seeds
		virtual bool on_extended(int /*length*/, int /*msg*/,
			buffer::const_interval /*body*/)
		{ return false; }

		// this is not called for web seeds
		virtual bool on_unknown_message(int /*length*/, int /*msg*/,
			buffer::const_interval /*body*/)
		{ return false; }

		// called when a piece that this peer participated in either
		// fails or passes the hash_check
		virtual void on_piece_pass(int /*index*/) {}
		virtual void on_piece_failed(int /*index*/) {}

		// called aproximately once every second
		virtual void tick() {}

		// called each time a request message is to be sent. If true
		// is returned, the original request message won't be sent and
		// no other plugin will have this function called.
		virtual bool write_request(peer_request const&) { return false; }
	};

}

#endif

#endif // TORRENT_EXTENSIONS_HPP_INCLUDED

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, 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_LAZY_ENTRY_HPP_INCLUDED
#define TORRENT_LAZY_ENTRY_HPP_INCLUDED

#include <utility>
#include <vector>
#include <string>
#include <cstring>
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/size_type.hpp"
#include "libtorrent/error_code.hpp"

#if TORRENT_USE_IOSTREAM
#include <iosfwd>
#endif

namespace libtorrent
{
	struct lazy_entry;

	TORRENT_EXPORT char const* parse_int(char const* start, char const* end
		, char delimiter, boost::int64_t& val);

	// return 0 = success
	TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end
		, lazy_entry& ret, error_code& ec, int* error_pos = 0
		, int depth_limit = 1000, int item_limit = 1000000);

#ifndef TORRENT_NO_DEPRECATE
	// for backwards compatibility, does not report error code
	// deprecated in 0.16
	TORRENT_DEPRECATED_PREFIX
	TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end
		, lazy_entry& ret, int depth_limit = 1000, int item_limit = 1000000) TORRENT_DEPRECATED;
#endif

	struct pascal_string
	{
		pascal_string(char const* p, int l): len(l), ptr(p) {}
		int len;
		char const* ptr;
		bool operator<(pascal_string const& rhs) const
		{
			return std::memcmp(ptr, rhs.ptr, (std::min)(len, rhs.len)) < 0
				|| len < rhs.len;
		}
	};

	struct lazy_dict_entry;

	struct TORRENT_EXPORT lazy_entry
	{
		enum entry_type_t
		{
			none_t, dict_t, list_t, string_t, int_t
		};

		lazy_entry() : m_begin(0), m_len(0), m_size(0), m_capacity(0), m_type(none_t)
		{ m_data.start = 0; }

		entry_type_t type() const { return (entry_type_t)m_type; }

		// start points to the first decimal digit
		// length is the number of digits
		void construct_int(char const* start, int length)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = int_t;
			m_data.start = start;
			m_size = length;
			m_begin = start - 1; // include 'i'
			m_len = length + 2; // include 'e'
		}

		size_type int_value() const;

		// string functions
		// ================

		void construct_string(char const* start, int length);

		// the string is not null-terminated!
		char const* string_ptr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return m_data.start;
		}

		// this will return a null terminated string
		// it will write to the source buffer!
		char const* string_cstr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			const_cast<char*>(m_data.start)[m_size] = 0;
			return m_data.start;
		}

		pascal_string string_pstr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return pascal_string(m_data.start, m_size);
		}

		std::string string_value() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return std::string(m_data.start, m_size);
		}

		int string_length() const
		{ return m_size; }

		// dictionary functions
		// ====================

		void construct_dict(char const* begin)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = dict_t;
			m_size = 0;
			m_capacity = 0;
			m_begin = begin;
		}

		lazy_entry* dict_append(char const* name);
		void pop();
		lazy_entry* dict_find(char const* name);
		lazy_entry const* dict_find(char const* name) const
		{ return const_cast<lazy_entry*>(this)->dict_find(name); }

		std::string dict_find_string_value(char const* name) const;
		pascal_string dict_find_pstr(char const* name) const;
		size_type dict_find_int_value(char const* name, size_type default_val = 0) const;
		lazy_entry const* dict_find_dict(char const* name) const;
		lazy_entry const* dict_find_list(char const* name) const;
		lazy_entry const* dict_find_string(char const* name) const;
		lazy_entry const* dict_find_int(char const* name) const;

		std::pair<std::string, lazy_entry const*> dict_at(int i) const;

		int dict_size() const
		{
			TORRENT_ASSERT(m_type == dict_t);
			return m_size;
		}

		// list functions
		// ==============

		void construct_list(char const* begin)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = list_t;
			m_size = 0;
			m_capacity = 0;
			m_begin = begin;
		}

		lazy_entry* list_append();
		lazy_entry* list_at(int i)
		{
			TORRENT_ASSERT(m_type == list_t);
			TORRENT_ASSERT(i < int(m_size));
			return &m_data.list[i];
		}
		lazy_entry const* list_at(int i) const
		{ return const_cast<lazy_entry*>(this)->list_at(i); }

		std::string list_string_value_at(int i) const;
		pascal_string list_pstr_at(int i) const;
		size_type list_int_value_at(int i, size_type default_val = 0) const;

		int list_size() const
		{
			TORRENT_ASSERT(m_type == list_t);
			return int(m_size);
		}

		// end points one byte passed last byte
		void set_end(char const* end)
		{
			TORRENT_ASSERT(end > m_begin);
			m_len = end - m_begin;
		}

		void clear();

		// releases ownership of any memory allocated
		void release()
		{
			m_data.start = 0;
			m_size = 0;
			m_capacity = 0;
			m_type = none_t;
		}

		~lazy_entry()
		{ clear(); }

		// returns pointers into the source buffer where
		// this entry has its bencoded data
		std::pair<char const*, int> data_section() const;

		void swap(lazy_entry& e)
		{
			using std::swap;
			boost::uint32_t tmp = e.m_type;
			e.m_type = m_type;
			m_type = tmp;
			tmp = e.m_capacity;
			e.m_capacity = m_capacity;
			m_capacity = tmp;
			swap(m_data.start, e.m_data.start);
			swap(m_size, e.m_size);
			swap(m_begin, e.m_begin);
			swap(m_len, e.m_len);
		}

	private:

		union data_t
		{
			lazy_dict_entry* dict;
			lazy_entry* list;
			char const* start;
		} m_data;

		// used for dictionaries and lists to record the range
		// in the original buffer they are based on
		char const* m_begin;
		// the number of bytes this entry extends in the
		// bencoded byffer
		boost::uint32_t m_len;

		// if list or dictionary, the number of items
		boost::uint32_t m_size;
		// if list or dictionary, allocated number of items
		boost::uint32_t m_capacity:29;
		// element type (dict, list, int, string)
		boost::uint32_t m_type:3;

		// non-copyable
		lazy_entry(lazy_entry const&);
		lazy_entry const& operator=(lazy_entry const&);
	};

	struct lazy_dict_entry
	{
		char const* name;
		lazy_entry val;
	};

	TORRENT_EXPORT std::string print_entry(lazy_entry const& e
		, bool single_line = false, int indent = 0);
#if TORRENT_USE_IOSTREAM
	TORRENT_EXPORT std::ostream& operator<<(std::ostream& os, lazy_entry const& e);
#endif

}

#endif

<commit_msg>attempt to fix msvc12 build<commit_after>/*

Copyright (c) 2003, 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_LAZY_ENTRY_HPP_INCLUDED
#define TORRENT_LAZY_ENTRY_HPP_INCLUDED

#include <utility>
#include <vector>
#include <string>
#include <cstring>
#include <algorithm>
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/size_type.hpp"
#include "libtorrent/error_code.hpp"

#if TORRENT_USE_IOSTREAM
#include <iosfwd>
#endif

namespace libtorrent
{
	struct lazy_entry;

	TORRENT_EXPORT char const* parse_int(char const* start, char const* end
		, char delimiter, boost::int64_t& val);

	// return 0 = success
	TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end
		, lazy_entry& ret, error_code& ec, int* error_pos = 0
		, int depth_limit = 1000, int item_limit = 1000000);

#ifndef TORRENT_NO_DEPRECATE
	// for backwards compatibility, does not report error code
	// deprecated in 0.16
	TORRENT_DEPRECATED_PREFIX
	TORRENT_EXPORT int lazy_bdecode(char const* start, char const* end
		, lazy_entry& ret, int depth_limit = 1000, int item_limit = 1000000) TORRENT_DEPRECATED;
#endif

	struct pascal_string
	{
		pascal_string(char const* p, int l): len(l), ptr(p) {}
		int len;
		char const* ptr;
		bool operator<(pascal_string const& rhs) const
		{
			return std::memcmp(ptr, rhs.ptr, (std::min)(len, rhs.len)) < 0
				|| len < rhs.len;
		}
	};

	struct lazy_dict_entry;

	struct TORRENT_EXPORT lazy_entry
	{
		enum entry_type_t
		{
			none_t, dict_t, list_t, string_t, int_t
		};

		lazy_entry() : m_begin(0), m_len(0), m_size(0), m_capacity(0), m_type(none_t)
		{ m_data.start = 0; }

		entry_type_t type() const { return (entry_type_t)m_type; }

		// start points to the first decimal digit
		// length is the number of digits
		void construct_int(char const* start, int length)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = int_t;
			m_data.start = start;
			m_size = length;
			m_begin = start - 1; // include 'i'
			m_len = length + 2; // include 'e'
		}

		size_type int_value() const;

		// string functions
		// ================

		void construct_string(char const* start, int length);

		// the string is not null-terminated!
		char const* string_ptr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return m_data.start;
		}

		// this will return a null terminated string
		// it will write to the source buffer!
		char const* string_cstr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			const_cast<char*>(m_data.start)[m_size] = 0;
			return m_data.start;
		}

		pascal_string string_pstr() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return pascal_string(m_data.start, m_size);
		}

		std::string string_value() const
		{
			TORRENT_ASSERT(m_type == string_t);
			return std::string(m_data.start, m_size);
		}

		int string_length() const
		{ return m_size; }

		// dictionary functions
		// ====================

		void construct_dict(char const* begin)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = dict_t;
			m_size = 0;
			m_capacity = 0;
			m_begin = begin;
		}

		lazy_entry* dict_append(char const* name);
		void pop();
		lazy_entry* dict_find(char const* name);
		lazy_entry const* dict_find(char const* name) const
		{ return const_cast<lazy_entry*>(this)->dict_find(name); }

		std::string dict_find_string_value(char const* name) const;
		pascal_string dict_find_pstr(char const* name) const;
		size_type dict_find_int_value(char const* name, size_type default_val = 0) const;
		lazy_entry const* dict_find_dict(char const* name) const;
		lazy_entry const* dict_find_list(char const* name) const;
		lazy_entry const* dict_find_string(char const* name) const;
		lazy_entry const* dict_find_int(char const* name) const;

		std::pair<std::string, lazy_entry const*> dict_at(int i) const;

		int dict_size() const
		{
			TORRENT_ASSERT(m_type == dict_t);
			return m_size;
		}

		// list functions
		// ==============

		void construct_list(char const* begin)
		{
			TORRENT_ASSERT(m_type == none_t);
			m_type = list_t;
			m_size = 0;
			m_capacity = 0;
			m_begin = begin;
		}

		lazy_entry* list_append();
		lazy_entry* list_at(int i)
		{
			TORRENT_ASSERT(m_type == list_t);
			TORRENT_ASSERT(i < int(m_size));
			return &m_data.list[i];
		}
		lazy_entry const* list_at(int i) const
		{ return const_cast<lazy_entry*>(this)->list_at(i); }

		std::string list_string_value_at(int i) const;
		pascal_string list_pstr_at(int i) const;
		size_type list_int_value_at(int i, size_type default_val = 0) const;

		int list_size() const
		{
			TORRENT_ASSERT(m_type == list_t);
			return int(m_size);
		}

		// end points one byte passed last byte
		void set_end(char const* end)
		{
			TORRENT_ASSERT(end > m_begin);
			m_len = end - m_begin;
		}

		void clear();

		// releases ownership of any memory allocated
		void release()
		{
			m_data.start = 0;
			m_size = 0;
			m_capacity = 0;
			m_type = none_t;
		}

		~lazy_entry()
		{ clear(); }

		// returns pointers into the source buffer where
		// this entry has its bencoded data
		std::pair<char const*, int> data_section() const;

		void swap(lazy_entry& e)
		{
			using std::swap;
			boost::uint32_t tmp = e.m_type;
			e.m_type = m_type;
			m_type = tmp;
			tmp = e.m_capacity;
			e.m_capacity = m_capacity;
			m_capacity = tmp;
			swap(m_data.start, e.m_data.start);
			swap(m_size, e.m_size);
			swap(m_begin, e.m_begin);
			swap(m_len, e.m_len);
		}

	private:

		union data_t
		{
			lazy_dict_entry* dict;
			lazy_entry* list;
			char const* start;
		} m_data;

		// used for dictionaries and lists to record the range
		// in the original buffer they are based on
		char const* m_begin;
		// the number of bytes this entry extends in the
		// bencoded byffer
		boost::uint32_t m_len;

		// if list or dictionary, the number of items
		boost::uint32_t m_size;
		// if list or dictionary, allocated number of items
		boost::uint32_t m_capacity:29;
		// element type (dict, list, int, string)
		boost::uint32_t m_type:3;

		// non-copyable
		lazy_entry(lazy_entry const&);
		lazy_entry const& operator=(lazy_entry const&);
	};

	struct lazy_dict_entry
	{
		char const* name;
		lazy_entry val;
	};

	TORRENT_EXPORT std::string print_entry(lazy_entry const& e
		, bool single_line = false, int indent = 0);
#if TORRENT_USE_IOSTREAM
	TORRENT_EXPORT std::ostream& operator<<(std::ostream& os, lazy_entry const& e);
#endif

}

#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_PROXY_BASE_HPP_INCLUDED
#define TORRENT_PROXY_BASE_HPP_INCLUDED

#include "libtorrent/io.hpp"
#include "libtorrent/socket.hpp"
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/function.hpp>
#include <asio/read.hpp>
#include <asio/write.hpp>

namespace libtorrent {

class proxy_base : boost::noncopyable
{
public:

	typedef stream_socket::lowest_layer_type lowest_layer_type;
	typedef stream_socket::endpoint_type endpoint_type;
	typedef stream_socket::protocol_type protocol_type;

	explicit proxy_base(asio::io_service& io_service)
		: m_sock(io_service)
		, m_resolver(io_service)
	{}

	void set_proxy(std::string hostname, int port)
	{
		m_hostname = hostname;
		m_port = port;
	}

	template <class Mutable_Buffers, class Handler>
	void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
	{
		m_sock.async_read_some(buffers, handler);
	}

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
	{
		return m_sock.read_some(buffers, ec);
	}

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers)
	{
		return m_sock.read_some(buffers);
	}

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc)
	{
		m_sock.io_control(ioc);
	}

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc, asio::error_code& ec)
	{
		m_sock.io_control(ioc, ec);
	}

	template <class Const_Buffers, class Handler>
	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
	{
		m_sock.async_write_some(buffers, handler);
	}

	void bind(endpoint_type const& endpoint)
	{
		m_sock.bind(endpoint);
	}

	void bind(endpoint_type const& endpoint, asio::error_code& ec)
	{
		m_sock.bind(endpoint, ec);
	}

	void open(protocol_type const& p)
	{
		m_sock.open(p);
	}

	void open(protocol_type const& p, asio::error_code& ec)
	{
		m_sock.open(p, ec);
	}

	void close()
	{
		m_remote_endpoint = endpoint_type();
		m_sock.close();
	}

	void close(asio::error_code& ec)
	{
		m_sock.close(ec);
		m_resolver.cancel();
	}

	endpoint_type remote_endpoint()
	{
		return m_remote_endpoint;
	}

	endpoint_type remote_endpoint(asio::error_code& ec)
	{
		return m_remote_endpoint;
	}

	endpoint_type local_endpoint()
	{
		return m_sock.local_endpoint();
	}

	endpoint_type local_endpoint(asio::error_code& ec)
	{
		return m_sock.local_endpoint(ec);
	}

	asio::io_service& io_service()
	{
		return m_sock.io_service();
	}

	lowest_layer_type& lowest_layer()
	{
		return m_sock.lowest_layer();
	}

protected:

	stream_socket m_sock;
	std::string m_hostname;
	int m_port;

	endpoint_type m_remote_endpoint;

	tcp::resolver m_resolver;
};

}

#endif

<commit_msg>proxy_base shutdown 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_PROXY_BASE_HPP_INCLUDED
#define TORRENT_PROXY_BASE_HPP_INCLUDED

#include "libtorrent/io.hpp"
#include "libtorrent/socket.hpp"
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/function.hpp>
#include <asio/read.hpp>
#include <asio/write.hpp>

namespace libtorrent {

class proxy_base : boost::noncopyable
{
public:

	typedef stream_socket::lowest_layer_type lowest_layer_type;
	typedef stream_socket::endpoint_type endpoint_type;
	typedef stream_socket::protocol_type protocol_type;

	explicit proxy_base(asio::io_service& io_service)
		: m_sock(io_service)
		, m_resolver(io_service)
	{}

	void set_proxy(std::string hostname, int port)
	{
		m_hostname = hostname;
		m_port = port;
	}

	template <class Mutable_Buffers, class Handler>
	void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
	{
		m_sock.async_read_some(buffers, handler);
	}

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
	{
		return m_sock.read_some(buffers, ec);
	}

	template <class Mutable_Buffers>
	std::size_t read_some(Mutable_Buffers const& buffers)
	{
		return m_sock.read_some(buffers);
	}

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc)
	{
		m_sock.io_control(ioc);
	}

	template <class IO_Control_Command>
	void io_control(IO_Control_Command& ioc, asio::error_code& ec)
	{
		m_sock.io_control(ioc, ec);
	}

	template <class Const_Buffers, class Handler>
	void async_write_some(Const_Buffers const& buffers, Handler const& handler)
	{
		m_sock.async_write_some(buffers, handler);
	}

	void bind(endpoint_type const& endpoint)
	{
		m_sock.bind(endpoint);
	}

	void bind(endpoint_type const& endpoint, asio::error_code& ec)
	{
		m_sock.bind(endpoint, ec);
	}

	void open(protocol_type const& p)
	{
		m_sock.open(p);
	}

	void open(protocol_type const& p, asio::error_code& ec)
	{
		m_sock.open(p, ec);
	}

	void close()
	{
		m_remote_endpoint = endpoint_type();
		m_sock.close();
		m_resolver.cancel();
	}

	void close(asio::error_code& ec)
	{
		m_sock.close(ec);
		m_resolver.cancel();
	}

	endpoint_type remote_endpoint()
	{
		return m_remote_endpoint;
	}

	endpoint_type remote_endpoint(asio::error_code& ec)
	{
		return m_remote_endpoint;
	}

	endpoint_type local_endpoint()
	{
		return m_sock.local_endpoint();
	}

	endpoint_type local_endpoint(asio::error_code& ec)
	{
		return m_sock.local_endpoint(ec);
	}

	asio::io_service& io_service()
	{
		return m_sock.io_service();
	}

	lowest_layer_type& lowest_layer()
	{
		return m_sock.lowest_layer();
	}

protected:

	stream_socket m_sock;
	std::string m_hostname;
	int m_port;

	endpoint_type m_remote_endpoint;

	tcp::resolver m_resolver;
};

}

#endif

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_MARKER_HELPERS_HPP
#define MAPNIK_MARKER_HELPERS_HPP

#include <mapnik/feature.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_type.hpp>
#include <mapnik/geometry_centroid.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/marker.hpp> // for svg_storage_type
#include <mapnik/markers_placement.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/vertex_processor.hpp>
#include <mapnik/renderer_common/apply_vertex_converter.hpp>
#include <mapnik/renderer_common/render_markers_symbolizer.hpp>

// agg
#include "agg_trans_affine.h"

// stl
#include <memory>

namespace mapnik {

struct clip_poly_tag;

using svg_attribute_type = agg::pod_bvector<svg::path_attributes>;

template <typename Detector>
struct vector_markers_dispatch : util::noncopyable
{
    vector_markers_dispatch(svg_path_ptr const& src,
                            svg_path_adapter & path,
                            svg_attribute_type const& attrs,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl const& feature,
                            attributes const& vars,
                            bool snap_to_pixels,
                            markers_renderer_context & renderer_context)
        : params_(src->bounding_box(), recenter(src) * marker_trans,
                  sym, feature, vars, scale_factor, snap_to_pixels)
        , renderer_context_(renderer_context)
        , src_(src)
        , path_(path)
        , attrs_(attrs)
        , detector_(detector)
    {}

    template <typename T>
    void add_path(T & path)
    {
        markers_placement_finder<T, Detector> placement_finder(
            params_.placement_method, path, detector_, params_.placement_params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, params_.ignore_placement))
        {
            agg::trans_affine matrix = params_.placement_params.tr;
            matrix.rotate(angle);
            matrix.translate(x, y);
            renderer_context_.render_marker(src_, path_, attrs_, params_, matrix);
        }
    }

protected:
    static agg::trans_affine recenter(svg_path_ptr const& src)
    {
        coord2d center = src->bounding_box().center();
        return agg::trans_affine_translation(-center.x, -center.y);
    }

    markers_dispatch_params params_;
    markers_renderer_context & renderer_context_;
    svg_path_ptr const& src_;
    svg_path_adapter & path_;
    svg_attribute_type const& attrs_;
    Detector & detector_;
};

template <typename Detector>
struct raster_markers_dispatch : util::noncopyable
{
    raster_markers_dispatch(image_rgba8 const& src,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl const& feature,
                            attributes const& vars,
                            markers_renderer_context & renderer_context)
        : params_(box2d<double>(0, 0, src.width(), src.height()),
                  marker_trans, sym, feature, vars, scale_factor)
        , renderer_context_(renderer_context)
        , src_(src)
        , detector_(detector)
    {}

    template <typename T>
    void add_path(T & path)
    {
        markers_placement_finder<T, Detector> placement_finder(
            params_.placement_method, path, detector_, params_.placement_params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, params_.ignore_placement))
        {
            agg::trans_affine matrix = params_.placement_params.tr;
            matrix.rotate(angle);
            matrix.translate(x, y);
            renderer_context_.render_marker(src_, params_, matrix);
        }
    }

protected:
    markers_dispatch_params params_;
    markers_renderer_context & renderer_context_;
    image_rgba8 const& src_;
    Detector & detector_;
};

void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, attributes const& vars,
                   svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path);

bool push_explicit_style(svg_attribute_type const& src,
                         svg_attribute_type & dst,
                         symbolizer_base const& sym,
                         feature_impl & feature,
                         attributes const& vars);

void setup_transform_scaling(agg::trans_affine & tr,
                             double svg_width,
                             double svg_height,
                             mapnik::feature_impl & feature,
                             attributes const& vars,
                             symbolizer_base const& sym);

// Apply markers to a feature with multiple geometries

template <typename Converter, typename Processor>
void apply_markers_single(Converter & converter, Processor & proc, geometry::geometry<double> const& geom)
{
    geometry::geometry_types type = geometry::geometry_type(geom);

    if (type == geometry::geometry_types::Point)
    {
        geometry::point_vertex_adapter<double> va(geom.get<geometry::point<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::LineString)
    {
        geometry::line_string_vertex_adapter<double> va(geom.get<geometry::line_string<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::Polygon)
    {
        geometry::polygon_vertex_adapter<double> va(geom.get<geometry::polygon<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::MultiPoint)
    {
        for (auto const& pt : geom.get<geometry::multi_point<double>>())
        {
            geometry::point_vertex_adapter<double> va(pt);
            converter.apply(va, proc);
        }
    }
    else if (type == geometry::geometry_types::MultiLineString)
    {
        for (auto const& line : geom.get<geometry::multi_line_string<double>>())
        {
            geometry::line_string_vertex_adapter<double> va(line);
            converter.apply(va, proc);
        }
    }
    else if (type == geometry::geometry_types::MultiPolygon)
    {
        for (auto const& poly : geom.get<geometry::multi_polygon<double>>())
        {
            geometry::polygon_vertex_adapter<double> va(poly);
            converter.apply(va, proc);
        }
    }
}

template <typename Converter, typename Processor>
void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, Processor & proc, symbolizer_base const& sym)
{
    using apply_vertex_converter_type = detail::apply_vertex_converter<Converter,Processor>;
    apply_vertex_converter_type apply(converter, proc);
    auto const& geom = feature.get_geometry();
    geometry::geometry_types type = geometry::geometry_type(geom);

    if (type == geometry::geometry_types::Point
        ||
        type == geometry::geometry_types::LineString
        ||
        type == geometry::geometry_types::Polygon)
    {
        apply_markers_single(converter, proc, geom);
    }
    else
    {

        marker_multi_policy_enum multi_policy = get<marker_multi_policy_enum, keys::markers_multipolicy>(sym, feature, vars);
        marker_placement_enum placement = get<marker_placement_enum, keys::markers_placement_type>(sym, feature, vars);

        if (placement == MARKER_POINT_PLACEMENT &&
            multi_policy == MARKER_WHOLE_MULTI)
        {
            geometry::point<double> pt;
            // test if centroid is contained by bounding box
            if (geometry::centroid(geom, pt) && converter.disp_.args_.bbox.contains(pt.x, pt.y))
            {
                // unset any clipping since we're now dealing with a point
                converter.template unset<clip_poly_tag>();
                geometry::point_vertex_adapter<double> va(pt);
                converter.apply(va, proc);
            }
        }
        else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
                 multi_policy == MARKER_LARGEST_MULTI)
        {
            // Only apply to path with largest envelope area
            // TODO: consider using true area for polygon types
            if (type == geometry::geometry_types::MultiPolygon)
            {
                geometry::multi_polygon<double> const& multi_poly = mapnik::util::get<geometry::multi_polygon<double> >(geom);
                double maxarea = 0;
                geometry::polygon<double> const* largest = 0;
                for (geometry::polygon<double> const& poly : multi_poly)
                {
                    box2d<double> bbox = geometry::envelope(poly);
                    double area = bbox.width() * bbox.height();
                    if (area > maxarea)
                    {
                        maxarea = area;
                        largest = &poly;
                    }
                }
                if (largest)
                {
                    geometry::polygon_vertex_adapter<double> va(*largest);
                    converter.apply(va, proc);
                }
            }
            else
            {
                MAPNIK_LOG_WARN(marker_symbolizer) << "TODO: if you get here -> open an issue";
            }
        }
        else
        {
            if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
            {
                MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
            }
            if (type == geometry::geometry_types::GeometryCollection)
            {
                for (auto const& g : geom.get<geometry::geometry_collection<double>>())
                {
                    apply_markers_single(converter, proc, g);
                }
            }
            else
            {
                apply_markers_single(converter, proc, geom);
            }
        }
    }
}

}

#endif //MAPNIK_MARKER_HELPERS_HPP
<commit_msg>reuse `type`<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_MARKER_HELPERS_HPP
#define MAPNIK_MARKER_HELPERS_HPP

#include <mapnik/feature.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_type.hpp>
#include <mapnik/geometry_centroid.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/marker.hpp> // for svg_storage_type
#include <mapnik/markers_placement.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/vertex_processor.hpp>
#include <mapnik/renderer_common/apply_vertex_converter.hpp>
#include <mapnik/renderer_common/render_markers_symbolizer.hpp>

// agg
#include "agg_trans_affine.h"

// stl
#include <memory>

namespace mapnik {

struct clip_poly_tag;

using svg_attribute_type = agg::pod_bvector<svg::path_attributes>;

template <typename Detector>
struct vector_markers_dispatch : util::noncopyable
{
    vector_markers_dispatch(svg_path_ptr const& src,
                            svg_path_adapter & path,
                            svg_attribute_type const& attrs,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl const& feature,
                            attributes const& vars,
                            bool snap_to_pixels,
                            markers_renderer_context & renderer_context)
        : params_(src->bounding_box(), recenter(src) * marker_trans,
                  sym, feature, vars, scale_factor, snap_to_pixels)
        , renderer_context_(renderer_context)
        , src_(src)
        , path_(path)
        , attrs_(attrs)
        , detector_(detector)
    {}

    template <typename T>
    void add_path(T & path)
    {
        markers_placement_finder<T, Detector> placement_finder(
            params_.placement_method, path, detector_, params_.placement_params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, params_.ignore_placement))
        {
            agg::trans_affine matrix = params_.placement_params.tr;
            matrix.rotate(angle);
            matrix.translate(x, y);
            renderer_context_.render_marker(src_, path_, attrs_, params_, matrix);
        }
    }

protected:
    static agg::trans_affine recenter(svg_path_ptr const& src)
    {
        coord2d center = src->bounding_box().center();
        return agg::trans_affine_translation(-center.x, -center.y);
    }

    markers_dispatch_params params_;
    markers_renderer_context & renderer_context_;
    svg_path_ptr const& src_;
    svg_path_adapter & path_;
    svg_attribute_type const& attrs_;
    Detector & detector_;
};

template <typename Detector>
struct raster_markers_dispatch : util::noncopyable
{
    raster_markers_dispatch(image_rgba8 const& src,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl const& feature,
                            attributes const& vars,
                            markers_renderer_context & renderer_context)
        : params_(box2d<double>(0, 0, src.width(), src.height()),
                  marker_trans, sym, feature, vars, scale_factor)
        , renderer_context_(renderer_context)
        , src_(src)
        , detector_(detector)
    {}

    template <typename T>
    void add_path(T & path)
    {
        markers_placement_finder<T, Detector> placement_finder(
            params_.placement_method, path, detector_, params_.placement_params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, params_.ignore_placement))
        {
            agg::trans_affine matrix = params_.placement_params.tr;
            matrix.rotate(angle);
            matrix.translate(x, y);
            renderer_context_.render_marker(src_, params_, matrix);
        }
    }

protected:
    markers_dispatch_params params_;
    markers_renderer_context & renderer_context_;
    image_rgba8 const& src_;
    Detector & detector_;
};

void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, attributes const& vars,
                   svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path);

bool push_explicit_style(svg_attribute_type const& src,
                         svg_attribute_type & dst,
                         symbolizer_base const& sym,
                         feature_impl & feature,
                         attributes const& vars);

void setup_transform_scaling(agg::trans_affine & tr,
                             double svg_width,
                             double svg_height,
                             mapnik::feature_impl & feature,
                             attributes const& vars,
                             symbolizer_base const& sym);

// Apply markers to a feature with multiple geometries
template <typename Converter, typename Processor>
void apply_markers_single(Converter & converter, Processor & proc, geometry::geometry<double> const& geom, geometry::geometry_types type)
{
    if (type == geometry::geometry_types::Point)
    {
        geometry::point_vertex_adapter<double> va(geom.get<geometry::point<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::LineString)
    {
        geometry::line_string_vertex_adapter<double> va(geom.get<geometry::line_string<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::Polygon)
    {
        geometry::polygon_vertex_adapter<double> va(geom.get<geometry::polygon<double>>());
        converter.apply(va, proc);
    }
    else if (type == geometry::geometry_types::MultiPoint)
    {
        for (auto const& pt : geom.get<geometry::multi_point<double>>())
        {
            geometry::point_vertex_adapter<double> va(pt);
            converter.apply(va, proc);
        }
    }
    else if (type == geometry::geometry_types::MultiLineString)
    {
        for (auto const& line : geom.get<geometry::multi_line_string<double>>())
        {
            geometry::line_string_vertex_adapter<double> va(line);
            converter.apply(va, proc);
        }
    }
    else if (type == geometry::geometry_types::MultiPolygon)
    {
        for (auto const& poly : geom.get<geometry::multi_polygon<double>>())
        {
            geometry::polygon_vertex_adapter<double> va(poly);
            converter.apply(va, proc);
        }
    }
}

template <typename Converter, typename Processor>
void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, Processor & proc, symbolizer_base const& sym)
{
    using apply_vertex_converter_type = detail::apply_vertex_converter<Converter,Processor>;
    apply_vertex_converter_type apply(converter, proc);
    auto const& geom = feature.get_geometry();
    geometry::geometry_types type = geometry::geometry_type(geom);

    if (type == geometry::geometry_types::Point
        ||
        type == geometry::geometry_types::LineString
        ||
        type == geometry::geometry_types::Polygon)
    {
        apply_markers_single(converter, proc, geom, type);
    }
    else
    {

        marker_multi_policy_enum multi_policy = get<marker_multi_policy_enum, keys::markers_multipolicy>(sym, feature, vars);
        marker_placement_enum placement = get<marker_placement_enum, keys::markers_placement_type>(sym, feature, vars);

        if (placement == MARKER_POINT_PLACEMENT &&
            multi_policy == MARKER_WHOLE_MULTI)
        {
            geometry::point<double> pt;
            // test if centroid is contained by bounding box
            if (geometry::centroid(geom, pt) && converter.disp_.args_.bbox.contains(pt.x, pt.y))
            {
                // unset any clipping since we're now dealing with a point
                converter.template unset<clip_poly_tag>();
                geometry::point_vertex_adapter<double> va(pt);
                converter.apply(va, proc);
            }
        }
        else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
                 multi_policy == MARKER_LARGEST_MULTI)
        {
            // Only apply to path with largest envelope area
            // TODO: consider using true area for polygon types
            if (type == geometry::geometry_types::MultiPolygon)
            {
                geometry::multi_polygon<double> const& multi_poly = mapnik::util::get<geometry::multi_polygon<double> >(geom);
                double maxarea = 0;
                geometry::polygon<double> const* largest = 0;
                for (geometry::polygon<double> const& poly : multi_poly)
                {
                    box2d<double> bbox = geometry::envelope(poly);
                    double area = bbox.width() * bbox.height();
                    if (area > maxarea)
                    {
                        maxarea = area;
                        largest = &poly;
                    }
                }
                if (largest)
                {
                    geometry::polygon_vertex_adapter<double> va(*largest);
                    converter.apply(va, proc);
                }
            }
            else
            {
                MAPNIK_LOG_WARN(marker_symbolizer) << "TODO: if you get here -> open an issue";
            }
        }
        else
        {
            if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
            {
                MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
            }
            if (type == geometry::geometry_types::GeometryCollection)
            {
                for (auto const& g : geom.get<geometry::geometry_collection<double>>())
                {
                    apply_markers_single(converter, proc, g, geometry::geometry_type(g));
                }
            }
            else
            {
                apply_markers_single(converter, proc, geom, type);
            }
        }
    }
}

}

#endif //MAPNIK_MARKER_HELPERS_HPP
<|endoftext|>