//  (C) Copyright Gennadiy Rozental 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
//!@brief algorithms for comparing floating point values
// ***************************************************************************

#ifndef BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER
#define BOOST_TEST_FLOATING_POINT_COMPARISON_HPP_071894GER

// Boost.Test
#include <boost/test/detail/global_typedef.hpp>
#include <boost/test/tools/assertion_result.hpp>

// Boost
#include <boost/limits.hpp>  // for std::numeric_limits
#include <boost/static_assert.hpp>
#include <boost/assert.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/type_traits/is_array.hpp>
#include <boost/type_traits/conditional.hpp>
#include <boost/utility/enable_if.hpp>

// STL
#include <iosfwd>

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

//____________________________________________________________________________//

namespace boost {
namespace math {
namespace fpc {

// ************************************************************************** //
// **************              fpc::tolerance_based            ************** //
// ************************************************************************** //

//! @internal
//! Protects the instanciation of std::numeric_limits from non-supported types (eg. T=array)
template <typename T, bool enabled>
struct tolerance_based_delegate;

template <typename T>
struct tolerance_based_delegate<T, false> : mpl::false_ {};

template <typename T>
struct tolerance_based_delegate<T, true>
: mpl::bool_<
    is_floating_point<T>::value ||
    (!std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_specialized && !std::numeric_limits<T>::is_exact)>
{};

/*!@brief Indicates if a type can be compared using a tolerance scheme
 *
 * This is a metafunction that should evaluate to @c mpl::true_ if the type
 * @c T can be compared using a tolerance based method, typically for floating point
 * types.
 *
 * This metafunction can be specialized further to declare user types that are
 * floating point (eg. boost.multiprecision).
 */
template <typename T>
struct tolerance_based : tolerance_based_delegate<T, !is_array<T>::value >::type {};

// ************************************************************************** //
// **************                 fpc::strength                ************** //
// ************************************************************************** //

//! Method for comparing floating point numbers
enum strength {
    FPC_STRONG, //!< "Very close"   - equation 2' in docs, the default
    FPC_WEAK    //!< "Close enough" - equation 3' in docs.
};

// ************************************************************************** //
// **************         tolerance presentation types         ************** //
// ************************************************************************** //

template<typename FPT>
struct percent_tolerance_t {
    explicit    percent_tolerance_t( FPT v ) : m_value( v ) {}

    FPT m_value;
};

//____________________________________________________________________________//

template<typename FPT>
inline std::ostream& operator<<( std::ostream& out, percent_tolerance_t<FPT> t )
{
    return out << t.m_value;
}

//____________________________________________________________________________//

template<typename FPT>
inline percent_tolerance_t<FPT>
percent_tolerance( FPT v )
{
    return percent_tolerance_t<FPT>( v );
}

//____________________________________________________________________________//

// ************************************************************************** //
// **************                    details                   ************** //
// ************************************************************************** //

namespace fpc_detail {

// FPT is Floating-Point Type: float, double, long double or User-Defined.
template<typename FPT>
inline FPT
fpt_abs( FPT fpv )
{
    return fpv < static_cast<FPT>(0) ? -fpv : fpv;
}

//____________________________________________________________________________//

template<typename FPT>
struct fpt_specialized_limits
{
  static FPT    min_value() { return (std::numeric_limits<FPT>::min)(); }
  static FPT    max_value() { return (std::numeric_limits<FPT>::max)(); }
};

template<typename FPT>
struct fpt_non_specialized_limits
{
  static FPT    min_value() { return static_cast<FPT>(0); }
  static FPT    max_value() { return static_cast<FPT>(1000000); } // for our purposes it doesn't really matter what value is returned here
};

template<typename FPT>
struct fpt_limits : boost::conditional<std::numeric_limits<FPT>::is_specialized,
                                       fpt_specialized_limits<FPT>,
                                       fpt_non_specialized_limits<FPT>
                                      >::type
{};

//____________________________________________________________________________//

// both f1 and f2 are unsigned here
template<typename FPT>
inline FPT
safe_fpt_division( FPT f1, FPT f2 )
{
    // Avoid overflow.
    if( (f2 < static_cast<FPT>(1))  && (f1 > f2*fpt_limits<FPT>::max_value()) )
        return fpt_limits<FPT>::max_value();

    // Avoid underflow.
    if( (f1 == static_cast<FPT>(0)) ||
        ((f2 > static_cast<FPT>(1)) && (f1 < f2*fpt_limits<FPT>::min_value())) )
        return static_cast<FPT>(0);

    return f1/f2;
}

//____________________________________________________________________________//

template<typename FPT, typename ToleranceType>
inline FPT
fraction_tolerance( ToleranceType tolerance )
{
  return static_cast<FPT>(tolerance);
}

//____________________________________________________________________________//

template<typename FPT2, typename FPT>
inline FPT2
fraction_tolerance( percent_tolerance_t<FPT> tolerance )
{
    return FPT2(tolerance.m_value)*FPT2(0.01);
}

//____________________________________________________________________________//

} // namespace fpc_detail

// ************************************************************************** //
// **************             close_at_tolerance               ************** //
// ************************************************************************** //

/*!@brief Predicate for comparing floating point numbers
 *
 * This predicate is used to compare floating point numbers. In addition the comparison produces maximum
 * related differnce, which can be used to generate detailed error message
 * The methods for comparing floating points are detailed in the documentation. The method is chosen
 * by the @ref boost::math::fpc::strength given at construction.
 */
template<typename FPT>
class close_at_tolerance {
public:
    // Public typedefs
    typedef bool result_type;

    // Constructor
    template<typename ToleranceType>
    explicit    close_at_tolerance( ToleranceType tolerance, fpc::strength fpc_strength = FPC_STRONG )
    : m_fraction_tolerance( fpc_detail::fraction_tolerance<FPT>( tolerance ) )
    , m_strength( fpc_strength )
    , m_tested_rel_diff( 0 )
    {
        BOOST_ASSERT_MSG( m_fraction_tolerance >= FPT(0), "tolerance must not be negative!" ); // no reason for tolerance to be negative
    }

    // Access methods
    //! Returns the tolerance
    FPT                 fraction_tolerance() const  { return m_fraction_tolerance; }

    //! Returns the comparison method
    fpc::strength       strength() const            { return m_strength; }

    //! Returns the failing fraction
    FPT                 tested_rel_diff() const     { return m_tested_rel_diff; }

    /*! Compares two floating point numbers a and b such that their "left" relative difference |a-b|/a and/or
     * "right" relative difference |a-b|/b does not exceed specified relative (fraction) tolerance.
     *
     *  @param[in] left first floating point number to be compared
     *  @param[in] right second floating point number to be compared
     *
     * What is reported by @c tested_rel_diff in case of failure depends on the comparison method:
     * - for @c FPC_STRONG: the max of the two fractions
     * - for @c FPC_WEAK: the min of the two fractions
     * The rationale behind is to report the tolerance to set in order to make a test pass.
     */
    bool                operator()( FPT left, FPT right ) const
    {
        FPT diff              = fpc_detail::fpt_abs<FPT>( left - right );
        FPT fraction_of_right = fpc_detail::safe_fpt_division( diff, fpc_detail::fpt_abs( right ) );
        FPT fraction_of_left  = fpc_detail::safe_fpt_division( diff, fpc_detail::fpt_abs( left ) );

        FPT max_rel_diff = (std::max)( fraction_of_left, fraction_of_right );
        FPT min_rel_diff = (std::min)( fraction_of_left, fraction_of_right );

        m_tested_rel_diff = m_strength == FPC_STRONG ? max_rel_diff : min_rel_diff;

        return m_tested_rel_diff <= m_fraction_tolerance;
    }

private:
    // Data members
    FPT                 m_fraction_tolerance;
    fpc::strength       m_strength;
    mutable FPT         m_tested_rel_diff;
};

// ************************************************************************** //
// **************            small_with_tolerance              ************** //
// ************************************************************************** //

/*!@brief Predicate for comparing floating point numbers against 0
 *
 * Serves the same purpose as boost::math::fpc::close_at_tolerance, but used when one
 * of the operand is null.
 */
template<typename FPT>
class small_with_tolerance {
public:
    // Public typedefs
    typedef bool result_type;

    // Constructor
    explicit    small_with_tolerance( FPT tolerance ) // <= absolute tolerance
    : m_tolerance( tolerance )
    {
        BOOST_ASSERT( m_tolerance >= FPT(0) ); // no reason for the tolerance to be negative
    }

    // Action method
    bool        operator()( FPT fpv ) const
    {
        return fpc::fpc_detail::fpt_abs( fpv ) <= m_tolerance;
    }

private:
    // Data members
    FPT         m_tolerance;
};

// ************************************************************************** //
// **************                  is_small                    ************** //
// ************************************************************************** //

template<typename FPT>
inline bool
is_small( FPT fpv, FPT tolerance )
{
    return small_with_tolerance<FPT>( tolerance )( fpv );
}

//____________________________________________________________________________//

} // namespace fpc
} // namespace math
} // namespace boost

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

#endif // BOOST_FLOATING_POINT_COMAPARISON_HPP_071894GER


//==============================================================================
//         Copyright 2003 - 2013   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2013   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <boost/simd/ieee/include/functions/saturate.hpp>
#include <boost/simd/sdk/simd/logical.hpp>

#include <boost/dispatch/functor/meta/call.hpp>
#include <nt2/sdk/unit/tests/ulp.hpp>
#include <nt2/sdk/unit/tests/type_expr.hpp>
#include <nt2/sdk/unit/module.hpp>
#include <boost/simd/sdk/config.hpp>
#include <boost/simd/sdk/simd/io.hpp>
#include <boost/dispatch/meta/as_integer.hpp>
#include <boost/dispatch/meta/downgrade.hpp>
#include <boost/simd/include/functions/splat.hpp>

#include <boost/simd/include/constants/valmax.hpp>
#include <boost/simd/include/constants/valmin.hpp>
#include <boost/simd/include/constants/inf.hpp>
#include <boost/simd/include/constants/minf.hpp>
#include <boost/simd/include/constants/nan.hpp>
#include <boost/simd/include/constants/zero.hpp>
#include <boost/simd/include/constants/mone.hpp>

NT2_TEST_CASE_TPL ( saturate,  BOOST_SIMD_SIMD_REAL_TYPES)
{
  using boost::simd::saturate;
  using boost::simd::tag::saturate_;
  using boost::simd::Valmax;
  using boost::simd::Valmin;
  using boost::simd::Inf;
  using boost::simd::Minf;
  using boost::simd::Nan;
  using boost::simd::splat;
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION                            ext_t;
  typedef typename boost::dispatch::meta::as_integer<T>::type        iT;
  typedef native<T,ext_t>                                            vT;
  typedef typename boost::dispatch::meta::as_integer<vT>::type      viT;
  // specific values tests
  NT2_TEST_ULP_EQUAL(splat<vT>(1),           saturate<viT>(splat<vT>(1ull        )), 0);
  NT2_TEST_ULP_EQUAL(splat<vT>(Valmax<iT>()),saturate<viT>(splat<vT>(T(Valmax<iT>())*2)), 0);
  NT2_TEST_ULP_EQUAL(splat<vT>(Valmin<iT>()),saturate<viT>(splat<vT>(T(Valmin<iT>())*2)), 0);
  NT2_TEST_ULP_EQUAL(splat<vT>(Valmin<iT>()),saturate<viT>(splat<vT>(Minf<T>())), 0);
  NT2_TEST_ULP_EQUAL(splat<vT>(Valmax<iT>()),saturate<viT>(splat<vT>(Inf<T>())), 0);
  NT2_TEST_ULP_EQUAL(Nan<vT>(),saturate<viT>(splat<vT>(Nan<T>())), 0);

}

NT2_TEST_CASE_TPL ( saturateu,  BOOST_SIMD_SIMD_INTEGRAL_TYPES)
{
  using boost::simd::saturate;
  using boost::simd::tag::saturate_;
  using boost::simd::Valmax;
  using boost::simd::Valmin;
  using boost::simd::splat;
  using boost::simd::native;
  typedef BOOST_SIMD_DEFAULT_EXTENSION                            ext_t;
  typedef native<T,ext_t>                                            vT;
  typedef typename boost::dispatch::meta::downgrade<T>::type         dT;

  // specific values tests
  NT2_TEST_ULP_EQUAL(splat<vT>(Valmax <dT>()),           saturate<dT>(Valmax<vT>()), 0);
  NT2_TEST_ULP_EQUAL(splat<vT>(Valmin <dT>()),           saturate<dT>(Valmin<vT>()), 0);
}


/* CirKit: A circuit toolkit
 * Copyright (C) 2009-2015  University of Bremen
 * Copyright (C) 2015-2017  EPFL
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE truth_table

#include <boost/test/unit_test.hpp>
#include <boost/test/output_test_stream.hpp>

#include <reversible/truth_table.hpp>
#include <reversible/utils/truth_table_helpers.hpp>

BOOST_AUTO_TEST_CASE(simple)
{
  using boost::test_tools::output_test_stream;

  using namespace cirkit;

  binary_truth_table spec;

  spec.add_entry( number_to_truth_table_cube( 0u, 2u ), number_to_truth_table_cube( 0u, 2u ) );
  spec.add_entry( number_to_truth_table_cube( 1u, 2u ), number_to_truth_table_cube( 1u, 2u ) );
  spec.add_entry( number_to_truth_table_cube( 2u, 2u ), number_to_truth_table_cube( 3u, 2u ) );
  spec.add_entry( number_to_truth_table_cube( 3u, 2u ), number_to_truth_table_cube( 2u, 2u ) );

  output_test_stream output;
  output << spec;

  BOOST_CHECK( !output.is_empty( false ) );
  BOOST_CHECK( output.is_equal( "00 00\n01 01\n10 11\n11 10\n" ) );

  bitset_vector_t tt_vec = truth_table_to_bitset_vector( spec );
  BOOST_CHECK( tt_vec.size() == 4u );
  BOOST_CHECK( tt_vec[0u] == boost::dynamic_bitset<>( 2u, 0u ) );
  BOOST_CHECK( tt_vec[1u] == boost::dynamic_bitset<>( 2u, 1u ) );
  BOOST_CHECK( tt_vec[2u] == boost::dynamic_bitset<>( 2u, 3u ) );
  BOOST_CHECK( tt_vec[3u] == boost::dynamic_bitset<>( 2u, 2u ) );

  for ( unsigned i = 0u; i < 4u; ++i )
  {
    std::cout << boost::dynamic_bitset<>( 2u, i ) << " <-> " << tt_vec[i] << std::endl;
  }
}

// Local Variables:
// c-basic-offset: 2
// eval: (c-set-offset 'substatement-open 0)
// eval: (c-set-offset 'innamespace 0)
// End:


// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test

// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to 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)

#include <string>
#include <sstream>

#include <algorithms/test_distance.hpp>

#include <boost/mpl/if.hpp>
#include <boost/array.hpp>

#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/adapted/c_array.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>

#include <test_common/test_point.hpp>
#include <test_geometries/custom_segment.hpp>
#include <test_geometries/wrapped_boost_array.hpp>

// includes for multi-geometries
#include <boost/geometry/multi/geometries/multi_point.hpp>
#include <boost/geometry/multi/geometries/multi_linestring.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>
#include <boost/geometry/multi/io/wkt/read.hpp>

#include <boost/variant/variant.hpp>

BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(cs::cartesian)
BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)

// Register boost array as a linestring
namespace boost { namespace geometry { namespace traits
{
template <typename Point, std::size_t PointCount>
struct tag< boost::array<Point, PointCount> >
{
    typedef linestring_tag type;
};

}}}

template <typename P>
void test_distance_point()
{
    namespace services = bg::strategy::distance::services;
    typedef typename bg::default_distance_result<P>::type return_type;

    // Basic, trivial test

    P p1;
    bg::set<0>(p1, 1);
    bg::set<1>(p1, 1);

    P p2;
    bg::set<0>(p2, 2);
    bg::set<1>(p2, 2);

    return_type d = bg::distance(p1, p2);
    BOOST_CHECK_CLOSE(d, return_type(1.4142135), 0.001);

    // Test specifying strategy manually
    typename services::default_strategy
        <
            bg::point_tag, bg::point_tag, P
        >::type strategy;

    d = bg::distance(p1, p2, strategy);
    BOOST_CHECK_CLOSE(d, return_type(1.4142135), 0.001);

    {
        // Test custom strategy
        BOOST_CONCEPT_ASSERT( (bg::concept::PointDistanceStrategy<taxicab_distance, P, P>) );

        typedef typename services::return_type<taxicab_distance, P, P>::type cab_return_type;
        BOOST_MPL_ASSERT((boost::is_same<cab_return_type, typename bg::coordinate_type<P>::type>));

        taxicab_distance tcd;
        cab_return_type d = bg::distance(p1, p2, tcd);

        BOOST_CHECK( bg::math::abs(d - cab_return_type(2)) <= cab_return_type(0.01) );
    }

    {
        // test comparability

        typedef typename services::default_strategy
            <
                bg::point_tag, bg::point_tag, P
            >::type strategy_type;
        typedef typename services::comparable_type<strategy_type>::type comparable_strategy_type;

        strategy_type strategy;
        comparable_strategy_type comparable_strategy = services::get_comparable<strategy_type>::apply(strategy);
        return_type comparable = services::result_from_distance<comparable_strategy_type, P, P>::apply(comparable_strategy, 3);

        BOOST_CHECK_CLOSE(comparable, return_type(9), 0.001);
    }
}

template <typename P>
void test_distance_segment()
{
    typedef typename bg::default_distance_result<P>::type return_type;

    P s1; bg::set<0>(s1, 1); bg::set<1>(s1, 1);
    P s2; bg::set<0>(s2, 4); bg::set<1>(s2, 4);

    // Check points left, right, projected-left, projected-right, on segment
    P p1; bg::set<0>(p1, 0); bg::set<1>(p1, 1);
    P p2; bg::set<0>(p2, 1); bg::set<1>(p2, 0);
    P p3; bg::set<0>(p3, 3); bg::set<1>(p3, 1);
    P p4; bg::set<0>(p4, 1); bg::set<1>(p4, 3);
    P p5; bg::set<0>(p5, 3); bg::set<1>(p5, 3);

    bg::model::referring_segment<P const> const seg(s1, s2);

    return_type d1 = bg::distance(p1, seg);
    return_type d2 = bg::distance(p2, seg);
    return_type d3 = bg::distance(p3, seg);
    return_type d4 = bg::distance(p4, seg);
    return_type d5 = bg::distance(p5, seg);

    BOOST_CHECK_CLOSE(d1, return_type(1), 0.001);
    BOOST_CHECK_CLOSE(d2, return_type(1), 0.001);
    BOOST_CHECK_CLOSE(d3, return_type(1.4142135), 0.001);
    BOOST_CHECK_CLOSE(d4, return_type(1.4142135), 0.001);
    BOOST_CHECK_CLOSE(d5, return_type(0), 0.001);

    // Reverse case: segment/point instead of point/segment
    return_type dr1 = bg::distance(seg, p1);
    return_type dr2 = bg::distance(seg, p2);

    BOOST_CHECK_CLOSE(dr1, d1, 0.001);
    BOOST_CHECK_CLOSE(dr2, d2, 0.001);

    // Test specifying strategy manually:
    // 1) point-point-distance
    typename bg::strategy::distance::services::default_strategy
        <
            bg::point_tag, bg::point_tag, P
        >::type pp_strategy;
    d1 = bg::distance(p1, seg, pp_strategy);
    BOOST_CHECK_CLOSE(d1, return_type(1), 0.001);

    // 2) point-segment-distance
    typename bg::strategy::distance::services::default_strategy
        <
            bg::point_tag, bg::segment_tag, P
        >::type ps_strategy;
    d1 = bg::distance(p1, seg, ps_strategy);
    BOOST_CHECK_CLOSE(d1, return_type(1), 0.001);

    // 3) custom point strategy
    taxicab_distance tcd;
    d1 = bg::distance(p1, seg, tcd);
    BOOST_CHECK_CLOSE(d1, return_type(1), 0.001);
}

template <typename Point, typename Geometry, typename T>
void test_distance_linear(std::string const& wkt_point, std::string const& wkt_geometry, T const& expected)
{
    Point p;
    bg::read_wkt(wkt_point, p);

    Geometry g;
    bg::read_wkt(wkt_geometry, g);

    typedef typename bg::default_distance_result<Point>::type return_type;
    return_type d = bg::distance(p, g);

    // For point-to-linestring (or point-to-polygon), both a point-strategy and a point-segment-strategy can be specified.
    // Test this.
    return_type ds1 = bg::distance(p, g, bg::strategy::distance::pythagoras<>());
    return_type ds2 = bg::distance(p, g, bg::strategy::distance::projected_point<>());

    BOOST_CHECK_CLOSE(d, return_type(expected), 0.001);
    BOOST_CHECK_CLOSE(ds1, return_type(expected), 0.001);
    BOOST_CHECK_CLOSE(ds2, return_type(expected), 0.001);
}

template <typename P>
void test_distance_array_as_linestring()
{
    typedef typename bg::default_distance_result<P>::type return_type;

    // Normal array does not have
    boost::array<P, 2> points;
    bg::set<0>(points[0], 1);
    bg::set<1>(points[0], 1);
    bg::set<0>(points[1], 3);
    bg::set<1>(points[1], 3);

    P p;
    bg::set<0>(p, 2);
    bg::set<1>(p, 1);

    return_type d = bg::distance(p, points);
    BOOST_CHECK_CLOSE(d, return_type(0.70710678), 0.001);

    bg::set<0>(p, 5); bg::set<1>(p, 5);
    d = bg::distance(p, points);
    BOOST_CHECK_CLOSE(d, return_type(2.828427), 0.001);
}

// code moved from the distance unit test in multi/algorithms -- start
template <typename Geometry1, typename Geometry2>
void test_distance(std::string const& wkt1, std::string const& wkt2, double expected)
{
    Geometry1 g1;
    Geometry2 g2;
    bg::read_wkt(wkt1, g1);
    bg::read_wkt(wkt2, g2);
    typename bg::default_distance_result<Geometry1, Geometry2>::type d = bg::distance(g1, g2);

    BOOST_CHECK_CLOSE(d, expected, 0.0001);
}

template <typename Geometry1, typename Geometry2, typename Strategy>
void test_distance(Strategy const& strategy, std::string const& wkt1,
                   std::string const& wkt2, double expected)
{
    Geometry1 g1;
    Geometry2 g2;
    bg::read_wkt(wkt1, g1);
    bg::read_wkt(wkt2, g2);
    typename bg::default_distance_result<Geometry1, Geometry2>::type d = bg::distance(g1, g2, strategy);

    BOOST_CHECK_CLOSE(d, expected, 0.0001);
}

template <typename P>
void test_2d()
{
    typedef bg::model::multi_point<P> mp;
    typedef bg::model::multi_linestring<bg::model::linestring<P> > ml;
    test_distance<P, P>("POINT(0 0)", "POINT(1 1)", sqrt(2.0));
    test_distance<P, mp>("POINT(0 0)", "MULTIPOINT((1 1),(1 0),(0 2))", 1.0);
    test_distance<mp, P>("MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0);
    test_distance<mp, mp>("MULTIPOINT((1 1),(1 0),(0 2))", "MULTIPOINT((2 2),(2 3))", sqrt(2.0));
    test_distance<P, ml>("POINT(0 0)", "MULTILINESTRING((1 1,2 2),(1 0,2 0),(0 2,0 3))", 1.0);
    test_distance<ml, P>("MULTILINESTRING((1 1,2 2),(1 0,2 0),(0 2,0 3))", "POINT(0 0)", 1.0);
    test_distance<ml, mp>("MULTILINESTRING((1 1,2 2),(1 0,2 0),(0 2,0 3))", "MULTIPOINT((0 0),(1 1))", 0.0);

    // Test with a strategy
    bg::strategy::distance::pythagoras<> pyth;
    test_distance<P, P>(pyth, "POINT(0 0)", "POINT(1 1)", sqrt(2.0));
    test_distance<P, mp>(pyth, "POINT(0 0)", "MULTIPOINT((1 1),(1 0),(0 2))", 1.0);
    test_distance<mp, P>(pyth, "MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0);
}

template <typename P>
void test_3d()
{
    typedef bg::model::multi_point<P> mp;
    test_distance<P, P>("POINT(0 0 0)", "POINT(1 1 1)", sqrt(3.0));
    test_distance<P, mp>("POINT(0 0 0)", "MULTIPOINT((1 1 1),(1 0 0),(0 1 2))", 1.0);
    test_distance<mp, mp>("MULTIPOINT((1 1 1),(1 0 0),(0 0 2))", "MULTIPOINT((2 2 2),(2 3 4))", sqrt(3.0));
}

template <typename P1, typename P2>
void test_mixed()
{
    typedef bg::model::multi_point<P1> mp1;
    typedef bg::model::multi_point<P2> mp2;

    test_distance<P1, P2>("POINT(0 0)", "POINT(1 1)", sqrt(2.0));

    test_distance<P1, mp1>("POINT(0 0)", "MULTIPOINT((1 1),(1 0),(0 2))", 1.0);
    test_distance<P1, mp2>("POINT(0 0)", "MULTIPOINT((1 1),(1 0),(0 2))", 1.0);
    test_distance<P2, mp1>("POINT(0 0)", "MULTIPOINT((1 1),(1 0),(0 2))", 1.0);
    test_distance<P2, mp2>("POINT(0 0)", "MULTIPOINT((1 1),(1 0),(0 2))", 1.0);

    // Test automatic reversal
    test_distance<mp1, P1>("MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0);
    test_distance<mp1, P2>("MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0);
    test_distance<mp2, P1>("MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0);
    test_distance<mp2, P2>("MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0);

    // Test multi-multi using different point types for each
    test_distance<mp1, mp2>("MULTIPOINT((1 1),(1 0),(0 2))", "MULTIPOINT((2 2),(2 3))", sqrt(2.0));

    // Test with a strategy
    using namespace bg::strategy::distance;

    test_distance<P1, P2>(pythagoras<>(), "POINT(0 0)", "POINT(1 1)", sqrt(2.0));

    test_distance<P1, mp1>(pythagoras<>(), "POINT(0 0)", "MULTIPOINT((1 1),(1 0),(0 2))", 1.0);
    test_distance<P1, mp2>(pythagoras<>(), "POINT(0 0)", "MULTIPOINT((1 1),(1 0),(0 2))", 1.0);
    test_distance<P2, mp1>(pythagoras<>(), "POINT(0 0)", "MULTIPOINT((1 1),(1 0),(0 2))", 1.0);
    test_distance<P2, mp2>(pythagoras<>(), "POINT(0 0)", "MULTIPOINT((1 1),(1 0),(0 2))", 1.0);

    // Most interesting: reversal AND a strategy (note that the stategy must be reversed automatically
    test_distance<mp1, P1>(pythagoras<>(), "MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0);
    test_distance<mp1, P2>(pythagoras<>(), "MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0);
    test_distance<mp2, P1>(pythagoras<>(), "MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0);
    test_distance<mp2, P2>(pythagoras<>(), "MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0);
}
// code moved from the distance unit test in multi/algorithms -- end

template <typename P>
void test_all()
{
    test_distance_point<P>();
    test_distance_segment<P>();
    test_distance_array_as_linestring<P>();

    test_geometry<P, bg::model::segment<P> >("POINT(1 3)", "LINESTRING(1 1,4 4)", sqrt(2.0));
    test_geometry<P, bg::model::segment<P> >("POINT(3 1)", "LINESTRING(1 1,4 4)", sqrt(2.0));

    test_geometry<P, P>("POINT(1 1)", "POINT(2 2)", sqrt(2.0));
    test_geometry<P, P>("POINT(0 0)", "POINT(0 3)", 3.0);
    test_geometry<P, P>("POINT(0 0)", "POINT(4 0)", 4.0);
    test_geometry<P, P>("POINT(0 3)", "POINT(4 0)", 5.0);
    test_geometry<P, bg::model::linestring<P> >("POINT(1 3)", "LINESTRING(1 1,4 4)", sqrt(2.0));
    test_geometry<P, bg::model::linestring<P> >("POINT(3 1)", "LINESTRING(1 1,4 4)", sqrt(2.0));
    test_geometry<P, bg::model::linestring<P> >("POINT(50 50)", "LINESTRING(50 40, 40 50)", sqrt(50.0));
    test_geometry<P, bg::model::linestring<P> >("POINT(50 50)", "LINESTRING(50 40, 40 50, 0 90)", sqrt(50.0));
    test_geometry<bg::model::linestring<P>, P>("LINESTRING(1 1,4 4)", "POINT(1 3)", sqrt(2.0));
    test_geometry<bg::model::linestring<P>, P>("LINESTRING(50 40, 40 50)", "POINT(50 50)", sqrt(50.0));
    test_geometry<bg::model::linestring<P>, P>("LINESTRING(50 40, 40 50, 0 90)", "POINT(50 50)", sqrt(50.0));

    // Rings
    test_geometry<P, bg::model::ring<P> >("POINT(1 3)", "POLYGON((1 1,4 4,5 0,1 1))", sqrt(2.0));
    test_geometry<P, bg::model::ring<P> >("POINT(3 1)", "POLYGON((1 1,4 4,5 0,1 1))", 0.0);
    // other way round
    test_geometry<bg::model::ring<P>, P>("POLYGON((1 1,4 4,5 0,1 1))", "POINT(3 1)", 0.0);
    // open ring
    test_geometry<P, bg::model::ring<P, true, false> >("POINT(1 3)", "POLYGON((4 4,5 0,1 1))", sqrt(2.0));

    // Polygons
    test_geometry<P, bg::model::polygon<P> >("POINT(1 3)", "POLYGON((1 1,4 4,5 0,1 1))", sqrt(2.0));
    test_geometry<P, bg::model::polygon<P> >("POINT(3 1)", "POLYGON((1 1,4 4,5 0,1 1))", 0.0);
    // other way round
    test_geometry<bg::model::polygon<P>, P>("POLYGON((1 1,4 4,5 0,1 1))", "POINT(3 1)", 0.0);
    // open polygon
    test_geometry<P, bg::model::polygon<P, true, false> >("POINT(1 3)", "POLYGON((4 4,5 0,1 1))", sqrt(2.0));

    // Polygons with holes
    std::string donut = "POLYGON ((0 0,1 9,8 1,0 0),(1 1,4 1,1 4,1 1))";
    test_geometry<P, bg::model::polygon<P> >("POINT(2 2)", donut, 0.5 * sqrt(2.0));
    test_geometry<P, bg::model::polygon<P> >("POINT(3 3)", donut, 0.0);
    // other way round
    test_geometry<bg::model::polygon<P>, P>(donut, "POINT(2 2)", 0.5 * sqrt(2.0));
    // open
    test_geometry<P, bg::model::polygon<P, true, false> >("POINT(2 2)", "POLYGON ((0 0,1 9,8 1),(1 1,4 1,1 4))", 0.5 * sqrt(2.0));

    // Should (currently) give compiler assertion
    // test_geometry<bg::model::polygon<P>, bg::model::polygon<P> >(donut, donut, 0.5 * sqrt(2.0));

    // DOES NOT COMPILE - cannot do read_wkt (because boost::array is not variably sized)
    // test_geometry<P, boost::array<P, 2> >("POINT(3 1)", "LINESTRING(1 1,4 4)", sqrt(2.0));

    test_geometry<P, test::wrapped_boost_array<P, 2> >("POINT(3 1)", "LINESTRING(1 1,4 4)", sqrt(2.0));

    test_distance_linear<P, bg::model::linestring<P> >("POINT(3 1)", "LINESTRING(1 1,4 4)", sqrt(2.0));
}

template <typename P>
void test_empty_input()
{
    P p;
    bg::model::linestring<P> line_empty;
    bg::model::polygon<P> poly_empty;
    bg::model::ring<P> ring_empty;
    bg::model::multi_point<P> mp_empty;
    bg::model::multi_linestring<bg::model::linestring<P> > ml_empty;

    test_empty_input(p, line_empty);
    test_empty_input(p, poly_empty);
    test_empty_input(p, ring_empty);

    test_empty_input(p, mp_empty);
    test_empty_input(p, ml_empty);
    test_empty_input(mp_empty, mp_empty);

    // Test behaviour if one of the inputs is empty
    bg::model::multi_point<P> mp;
    mp.push_back(p);
    test_empty_input(mp_empty, mp);
    test_empty_input(mp, mp_empty);
}

void test_large_integers()
{
    typedef bg::model::point<int, 2, bg::cs::cartesian> int_point_type;
    typedef bg::model::point<double, 2, bg::cs::cartesian> double_point_type;

    // point-point
    {
        std::string const a = "POINT(2544000 528000)";
        std::string const b = "POINT(2768040 528000)";
        int_point_type ia, ib;
        double_point_type da, db;
        bg::read_wkt(a, ia);
        bg::read_wkt(b, ib);
        bg::read_wkt(a, da);
        bg::read_wkt(b, db);

        BOOST_AUTO(idist, bg::distance(ia, ib));
        BOOST_AUTO(ddist, bg::distance(da, db));

        BOOST_CHECK_MESSAGE(std::abs(idist - ddist) < 0.1,
                "within<a double> different from within<an int>");
    }
    // Point-segment
    {
        std::string const a = "POINT(2600000 529000)";
        std::string const b = "LINESTRING(2544000 528000, 2768040 528000)";
        int_point_type ia;
        double_point_type da;
        bg::model::segment<int_point_type> ib;
        bg::model::segment<double_point_type> db;
        bg::read_wkt(a, ia);
        bg::read_wkt(b, ib);
        bg::read_wkt(a, da);
        bg::read_wkt(b, db);

        BOOST_AUTO(idist, bg::distance(ia, ib));
        BOOST_AUTO(ddist, bg::distance(da, db));

        BOOST_CHECK_MESSAGE(std::abs(idist - ddist) < 0.1,
                "within<a double> different from within<an int>");
    }
}

template <typename T>
void test_variant()
{
    typedef bg::model::point<T, 2, bg::cs::cartesian> point_type;
    typedef bg::model::segment<point_type> segment_type;
    typedef bg::model::box<point_type> box_type;
    typedef boost::variant<point_type, segment_type, box_type> variant_type;

    point_type point;
    std::string const point_li = "POINT(1 3)";
    bg::read_wkt(point_li, point);

    segment_type seg;
    std::string const seg_li = "LINESTRING(1 1,4 4)";
    bg::read_wkt(seg_li, seg);

    variant_type v1, v2;

    BOOST_MPL_ASSERT((
        boost::is_same
            <
                typename bg::distance_result
                    <
                        variant_type, variant_type, bg::default_strategy
                    >::type,
                double
            >
    ));

    // Default strategy
    v1 = point;
    v2 = point;
    BOOST_CHECK_CLOSE(bg::distance(v1, v2), bg::distance(point, point), 0.0001);
    BOOST_CHECK_CLOSE(bg::distance(v1, point), bg::distance(point, point), 0.0001);
    BOOST_CHECK_CLOSE(bg::distance(point, v2), bg::distance(point, point), 0.0001);
    v1 = point;
    v2 = seg;
    BOOST_CHECK_CLOSE(bg::distance(v1, v2), bg::distance(point, seg), 0.0001);
    BOOST_CHECK_CLOSE(bg::distance(v1, seg), bg::distance(point, seg), 0.0001);
    BOOST_CHECK_CLOSE(bg::distance(point, v2), bg::distance(point, seg), 0.0001);

    // User defined strategy
    v1 = point;
    v2 = point;
    bg::strategy::distance::haversine<double> s;
    //BOOST_CHECK_CLOSE(bg::distance(v1, v2, s), bg::distance(point, point, s), 0.0001);
    //BOOST_CHECK_CLOSE(bg::distance(v1, point, s), bg::distance(point, point, s), 0.0001);
    //BOOST_CHECK_CLOSE(bg::distance(point, v2, s), bg::distance(point, point, s), 0.0001);
}

int test_main(int, char* [])
{
#ifdef TEST_ARRAY
    //test_all<int[2]>();
    //test_all<float[2]>();
    //test_all<double[2]>();
    //test_all<test::test_point>(); // located here because of 3D
#endif

    test_large_integers();

    test_all<bg::model::d2::point_xy<int> >();
    test_all<boost::tuple<float, float> >();
    test_all<bg::model::d2::point_xy<float> >();
    test_all<bg::model::d2::point_xy<double> >();

#ifdef HAVE_TTMATH
    test_all<bg::model::d2::point_xy<ttmath_big> >();
#endif

    test_empty_input<bg::model::d2::point_xy<int> >();

    // below are the test cases moved here from the distance unit test
    // in test/multi/algorithms
    test_2d<boost::tuple<float, float> >();
    test_2d<bg::model::d2::point_xy<float> >();
    test_2d<bg::model::d2::point_xy<double> >();

    test_3d<boost::tuple<float, float, float> >();
    test_3d<bg::model::point<double, 3, bg::cs::cartesian> >();

    test_mixed<bg::model::d2::point_xy<float>, bg::model::d2::point_xy<double> >();

#ifdef HAVE_TTMATH
    test_2d<bg::model::d2::point_xy<ttmath_big> >();
    test_mixed<bg::model::d2::point_xy<ttmath_big>, bg::model::d2::point_xy<double> >();
#endif

    test_empty_input<bg::model::d2::point_xy<int> >();

    test_variant<double>();
    test_variant<int>();

    return 0;
}


//==============================================================================
//         Copyright 2003 - 2011 LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011 LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef BOOST_SIMD_OPERATOR_FUNCTIONS_SIMD_SSE_SSE2_PLUS_HPP_INCLUDED
#define BOOST_SIMD_OPERATOR_FUNCTIONS_SIMD_SSE_SSE2_PLUS_HPP_INCLUDED
#ifdef BOOST_SIMD_HAS_SSE2_SUPPORT

#include <boost/simd/operator/functions/plus.hpp>
#include <boost/dispatch/attributes.hpp>

namespace boost { namespace simd { namespace ext
{
  BOOST_DISPATCH_IMPLEMENT          ( plus_
                                    , boost::simd::tag::sse2_
                                    , (A0)
                                    , ((simd_<double_<A0>,boost::simd::tag::sse_>))
                                      ((simd_<double_<A0>,boost::simd::tag::sse_>))
                                    )
  {
    typedef A0 result_type;

    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_add_pd(a0,a1);
    }
  };

  BOOST_DISPATCH_IMPLEMENT          ( plus_
                                    , boost::simd::tag::sse2_
                                    , (A0)
                                    , ((simd_<single_<A0>,boost::simd::tag::sse_>))
                                      ((simd_<single_<A0>,boost::simd::tag::sse_>))
                                    )
  {
    typedef A0 result_type;

    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_add_ps(a0,a1);
    }
  };

  BOOST_DISPATCH_IMPLEMENT          ( plus_
                                    , boost::simd::tag::sse2_
                                    , (A0)
                                    , ((simd_<ints8_<A0>,boost::simd::tag::sse_>))
                                      ((simd_<ints8_<A0>,boost::simd::tag::sse_>))
                                    )
  {
    typedef A0 result_type;

    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_add_epi8(a0,a1);
    }
  };

  BOOST_DISPATCH_IMPLEMENT          ( plus_
                                    , boost::simd::tag::sse2_
                                    , (A0)
                                    , ((simd_<ints16_<A0>,boost::simd::tag::sse_>))
                                      ((simd_<ints16_<A0>,boost::simd::tag::sse_>))
                                    )
  {
    typedef A0 result_type;

    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_add_epi16(a0,a1);
    }
  };

  BOOST_DISPATCH_IMPLEMENT          ( plus_
                                    , boost::simd::tag::sse2_
                                    , (A0)
                                    , ((simd_<ints32_<A0>,boost::simd::tag::sse_>))
                                      ((simd_<ints32_<A0>,boost::simd::tag::sse_>))
                                    )
  {
    typedef A0 result_type;

    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_add_epi32(a0,a1);
    }
  };

  BOOST_DISPATCH_IMPLEMENT          ( plus_
                                    , boost::simd::tag::sse2_
                                    , (A0)
                                    , ((simd_<ints64_<A0>,boost::simd::tag::sse_>))
                                      ((simd_<ints64_<A0>,boost::simd::tag::sse_>))
                                    )
  {
    typedef A0 result_type;

    BOOST_FORCEINLINE BOOST_SIMD_FUNCTOR_CALL_REPEAT(2)
    {
      return _mm_add_epi64(a0,a1);
    }
  };
} } }

#endif
#endif


#include "post_process/adminizer.hpp"

#include <mapnik/params.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/featureset.hpp>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/multi_point.hpp>
#include <boost/geometry/multi/geometries/multi_linestring.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry/io/wkt/write.hpp>

#include <queue> // for std::priority_queue<>

// NOTE: this is included only because it's where mapnik::coord2d is
// adapted to work with the boost::geometry stuff. we don't actually
// clip any polygons.
#include <mapnik/polygon_clipper.hpp>

namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;

using point_2d = bg::model::point<double, 2, bg::cs::cartesian>;
using box_2d = bg::model::box<point_2d>;
using linestring_2d = bg::model::linestring<point_2d>;
using multi_point_2d = bg::model::multi_point<point_2d>;
using multi_linestring_2d = bg::model::multi_linestring<linestring_2d>;
// the OGC standard states that the outer ring of a polygon should
// contain points ordered in a counter-clockwise direction, which is
// the opposide of boost::geometry's default, and that rings should
// be closed (i.e: first point == last point), which is the default.
using polygon_2d = bg::model::polygon<point_2d, false, true>;
using priority_queue = std::priority_queue<unsigned int, std::vector<unsigned int>,
                                           std::greater<unsigned int> >;

namespace {

/* type used in the rtree index to point to a polygon entry. the
 * rtree itself only indexes bounding boxes. */
typedef std::pair<box_2d, unsigned int> value;

/* type pointed to by the unsigned int index in the `value` type.
 * this stores the original admin polygon, the value of the
 * parameter it sets, and the index so that we can tell which
 * polygon comes 'first'.
 */
struct entry {
  entry(polygon_2d &&p, mapnik::value &&v, unsigned int i)
    : polygon(p), value(v), index(i) {
  }
  polygon_2d polygon;
  mapnik::value value;
  unsigned int index;
};

/* functor to collect indices of visited entries. this is then
 * used to figure out which admin areas were hit and in what
 * order. */
struct param_updater {
  bool m_collect;
  std::set<unsigned int> m_indices;
  bool m_finished;

  explicit param_updater(bool collect)
    : m_collect(collect)
    , m_indices()
    , m_finished(false) {
  }

  void operator()(const entry &e) {
    m_indices.insert(e.index);
    // early termination only if we're looking for the first admin
    // area and just found it.
    m_finished = (!m_collect) && (e.index == 0);
  }
};

/* update a feature based on a set of indices collected from hit
 * testing against admin polygons. */
void update_feature_params(const std::set<unsigned int> &indices,
                           bool collect,
                           const std::vector<entry> &entries,
                           mapnik::feature_ptr &&feat,
                           const std::string &param_name,
                           const mapnik::value_unicode_string &delimiter,
                           std::vector<mapnik::feature_ptr> &append_to) {
  append_to.emplace_back(feat);
  mapnik::feature_ptr &feature = append_to.back();

  if (!indices.empty()) {
    if (collect) {
      mapnik::value_unicode_string buffer;
      bool first = true;
      for (unsigned int i : indices) {
        if (first) {
          first = false;
        } else {
          buffer.append(delimiter);
        }
        buffer.append(entries[i].value.to_unicode());
      }
      feature->put_new(param_name, buffer);

    } else {
      const entry &e = entries[*indices.begin()];
      feature->put_new(param_name, e.value);
    }
  }
}

inline void update_feature_params(const param_updater &updater,
                                  const std::vector<entry> &entries,
                                  mapnik::feature_ptr &&feat,
                                  const std::string &param_name,
                                  const mapnik::value_unicode_string &delimiter,
                                  std::vector<mapnik::feature_ptr> &append_to) {
  update_feature_params(updater.m_indices, updater.m_collect,
                        entries, std::move(feat), param_name,
                        delimiter, append_to);
}

/* we convert Mapnik's representation of geometry to boost::geometry
 * models when we're doing the manipulation and hit testing. we really
 * shouldn't: we should adapt them instead. however, until we've done
 * this, we need conversion functions between Mapnik geometries and
 * boost::geometry::models and vice-versa. */
template <typename GeomType>
mapnik::geometry_type *to_mapnik_geom(const GeomType &g) {
  throw std::runtime_error("Unimplemented geometry type.");
}

template <>
mapnik::geometry_type *to_mapnik_geom<multi_point_2d>(const multi_point_2d &g) {
  mapnik::geometry_type *mg = new mapnik::geometry_type(mapnik::geometry_type::Point);
  for (auto const &point : g) {
    mg->move_to(point.get<0>(), point.get<1>());
  }
  return mg;
}

template <>
mapnik::geometry_type *to_mapnik_geom<multi_linestring_2d>(const multi_linestring_2d &g) {
  mapnik::geometry_type *mg = new mapnik::geometry_type(mapnik::geometry_type::LineString);
  for (auto const &line : g) {
    const size_t n_points = line.size();
    if (n_points > 0) {
      mg->move_to(line[0].get<0>(), line[0].get<1>());
      for (size_t i = 1; i < n_points; ++i) {
        mg->line_to(line[i].get<0>(), line[i].get<1>());
      }
    }
  }
  return mg;
}

mapnik::box2d<double> envelope(const std::vector<mapnik::feature_ptr> &layer) {
  mapnik::box2d<double> result;
  bool first = true;
  for (auto const &feature : layer) {
    if (first) {
      result = feature->envelope();
      first = false;

    } else {
      result.expand_to_include(feature->envelope());
    }
  }
  return result;
}

multi_point_2d make_boost_point(const mapnik::geometry_type &geom) {
/* Takes a mapnik geometry and makes a multi_point_2d from it. It has to be a
 * multipoint, since we don't know from geom.type() if it's a point or multipoint?
 */
  multi_point_2d points;
  double x = 0, y = 0;

  geom.rewind(0);

  unsigned int cmd = mapnik::SEG_END;

  while ((cmd = geom.vertex(&x, &y)) != mapnik::SEG_END) {
    points.push_back(bg::make<point_2d>(x, y));
  }
  return points;
}

multi_linestring_2d make_boost_linestring(const mapnik::geometry_type &geom) {
  multi_linestring_2d line;
  double x = 0, y = 0, prev_x = 0, prev_y = 0;

  geom.rewind(0);

  unsigned int cmd = mapnik::SEG_END;
  while ((cmd = geom.vertex(&x, &y)) != mapnik::SEG_END) {

    if (cmd == mapnik::SEG_MOVETO) {
      line.push_back(linestring_2d());
      line.back().push_back(bg::make<point_2d>(x, y));

    } else if (cmd == mapnik::SEG_LINETO) {
      if (std::abs(x - prev_x) < 1e-12 && std::abs(y - prev_y) < 1e-12) {
        continue;
      }

      line.back().push_back(bg::make<point_2d>(x, y));
    }

    prev_x = x;
    prev_y = y;
  }

  return line;
}

polygon_2d make_boost_polygon(const mapnik::geometry_type &geom) {
  polygon_2d poly;
  double x = 0, y = 0, prev_x = 0, prev_y = 0, first_x = 0, first_y = 0;
  unsigned int ring_count = 0;

  geom.rewind(0);

  unsigned int cmd = mapnik::SEG_END;
  while ((cmd = geom.vertex(&x, &y)) != mapnik::SEG_END) {

    if (cmd == mapnik::SEG_MOVETO) {
      if (ring_count == 0) {
        bg::append(poly, bg::make<point_2d>(x, y));

      } else {
        poly.inners().push_back(polygon_2d::inner_container_type::value_type());
        bg::append(poly.inners().back(), bg::make<point_2d>(x, y));
      }

      // save first point of ring to use when the ring is closed.
      first_x = x;
      first_y = y;

      ++ring_count;

    } else { // LINETO or CLOSE
      if (cmd == mapnik::SEG_CLOSE) {
        // x & y are 0 in SEG_CLOSE (at least, that seems to be the
        // convention in mapnik::geometry_type::close_path(), so we
        // ignore them and use the point we saved at the beginning
        // of the ring.
        x = first_x;
        y = first_y;
      }

      if (std::abs(x - prev_x) < 1e-12 && std::abs(y - prev_y) < 1e-12) {
        continue;
      }

      if (ring_count == 1) {
        bg::append(poly, bg::make<point_2d>(x, y));

      } else {
        bg::append(poly.inners().back(), bg::make<point_2d>(x, y));
      }
    }

    prev_x = x;
    prev_y = y;
  }

  return poly;
}

/* hack to perform actual splitting of a geometry into inside and
 * outside parts. this is the generic part, which works for most
 * geometry types.
 *
 * however, Mapnik can give us multi* geometry types, which are
 * not handled in boost::geometry 1.56, and which we have to
 * unpack manually in the template specialisations.
 */
template <typename GeomType>
inline void split_hack(const GeomType &geom, const polygon_2d &poly,
                       std::list<GeomType> &inside_out,
                       std::list<GeomType> &outside_out) {
  bg::intersection(geom, poly, inside_out);
  bg::difference(geom, poly, outside_out);
}

// specialisation for multipoint, currently not implemented in BG
template <>
inline void split_hack<multi_point_2d>(
  const multi_point_2d &multipoint,
  const polygon_2d &poly,
  std::list<multi_point_2d> &inside_out,
  std::list<multi_point_2d> &outside_out) {

  multi_point_2d inside_multi, outside_multi;
  for (auto const &point : multipoint) {
    if (bg::intersects(point, poly)) {
      inside_multi.push_back(point);
    } else {
      outside_multi.push_back(point);
    }
  }
  inside_out.emplace_back(std::move(inside_multi));
  outside_out.emplace_back(std::move(outside_multi));
}

// specialisation for multilinestring, currently not implemented in BG
template <>
inline void split_hack<multi_linestring_2d>(
  const multi_linestring_2d &multilinestring,
  const polygon_2d &poly,
  std::list<multi_linestring_2d> &inside_out,
  std::list<multi_linestring_2d> &outside_out) {

  multi_linestring_2d inside_multi, outside_multi;
  for (auto const &line : multilinestring) {
    bg::intersection(line, poly, inside_multi);
    bg::difference(line, poly, outside_multi);
  }

  inside_out.emplace_back(std::move(inside_multi));
  outside_out.emplace_back(std::move(outside_multi));
}

/* similarly, within() is unimplementd for some multi* types, so
 * we have to provide specialisations.
 */
template <typename GeomType>
inline bool within(const GeomType &geom, const polygon_2d &poly) {
  return bg::within(geom, poly);
}

template <>
inline bool within<multi_point_2d>(const multi_point_2d &geom, const polygon_2d &poly) {
  for (auto const &point : geom) {
    if (!bg::within(point, poly)) {
      return false;
    }
  }
  return true;
}

template <>
inline bool within<multi_linestring_2d>(const multi_linestring_2d &geom, const polygon_2d &poly) {
  for (auto const &line : geom) {
    if (!bg::within(line, poly)) {
      return false;
    }
  }
  return true;
}

/* similarly, disjoint() is unimplementd for some multi* types, so
 * we have to provide specialisations.
 */
template <typename GeomType>
inline bool disjoint(const GeomType &geom, const polygon_2d &poly) {
  return bg::disjoint(geom, poly);
}

template <>
inline bool disjoint<multi_point_2d>(const multi_point_2d &geom, const polygon_2d &poly) {
  for (auto const &point : geom) {
    if (!bg::disjoint(point, poly)) {
      return false;
    }
  }
  return true;
}

template <>
inline bool disjoint<multi_linestring_2d>(const multi_linestring_2d &geom, const polygon_2d &poly) {
  for (auto const &line : geom) {
    if (!bg::disjoint(line, poly)) {
      return false;
    }
  }
  return true;
}

/* implementation of the split between inside and outside parts of
 * the geometry with respect to a polygon. the logic here is the
 * same regardless of geometry type, but templated so that we can
 * deal with concrete boost geometry types.
 */
template <typename GeomType>
void split_impl(const GeomType &geom, const polygon_2d &poly,
                mapnik::feature_ptr &inside, mapnik::feature_ptr &outside) {
  if (within(geom, poly)) {
    inside->add_geometry(to_mapnik_geom(geom));

  } else if (disjoint(geom, poly)) {
    outside->add_geometry(to_mapnik_geom(geom));

  } else {
    // must be some part of the geometry which is inside and some
    // which is outside, so we'll need to split it.
    std::list<GeomType> inside_out, outside_out;

    // in an ideal world, here we would split the geometry. however,
    // because of multi* geometries, we have to hack it a bit.
    split_hack<GeomType>(geom, poly, inside_out, outside_out);

    for (const GeomType &g : inside_out) {
      inside->add_geometry(to_mapnik_geom(g));
    }
    for (const GeomType &g : outside_out) {
      outside->add_geometry(to_mapnik_geom(g));
    }
  }
}

/* split a geometry `geom` into the parts inside and outside of the
 * polygon `poly` and add the inside parts to `inside` and the outside
 * parts to `outside`.
 *
 * the implementation is extremely similar to `adminize_feature`, and
 * it would be nice to be able to factor out the common pattern.
 *
 * this function handles the "geometry type discovery" and hands off
 * the actual splitting to `split_impl`.
 */
void split(const mapnik::geometry_type &geom, const polygon_2d &poly,
           mapnik::feature_ptr &inside, mapnik::feature_ptr &outside) {
  if (geom.type() == mapnik::geometry_type::types::Point) {
    multi_point_2d multi_point = make_boost_point(geom);
    split_impl(multi_point, poly, inside, outside);

  } else if (geom.type() == mapnik::geometry_type::types::LineString) {
    multi_linestring_2d multi_line = make_boost_linestring(geom);
    split_impl(multi_line, poly, inside, outside);

  } else if (geom.type() == mapnik::geometry_type::types::Polygon) {
    polygon_2d poly2 = make_boost_polygon(geom);
    split_impl(poly2, poly, inside, outside);
  }
}

/* recursive function to visit a queue of remaining of hit admin polygon
 * indices in order of 'firstness' and split the geometries of `feat`
 * depending on what combination of admin polygons they are inside or
 * outside.
 *
 * this basically proceeds by looking at the first remaining index,
 * sorting the feature's geometries into the inside and outside parts
 * for the polygon for the top index and recursing where necessary
 * until all the geometries have been sorted as inside or outside each
 * of the admin polygons.
 */
void split_and_update(const std::set<unsigned int> &indices,
                      priority_queue remaining_indices,
                      bool collect,
                      const std::vector<entry> &entries,
                      mapnik::feature_ptr &&feat,
                      const std::string &param_name,
                      const mapnik::value_unicode_string &delimiter,
                      std::vector<mapnik::feature_ptr> &append_to) {
  if (remaining_indices.empty()) {
    update_feature_params(indices, collect, entries, std::move(feat),
                          param_name, delimiter, append_to);

  } else {
    unsigned int index = remaining_indices.top();
    remaining_indices.pop();
    const entry &e = entries[index];

    // TODO: copying the mapnik feature like this is very wasteful.
    // could either try instantiating lazily only when either is
    // non-empty, or do the whole thing with geometries and only
    // handle the features later?
    mapnik::feature_ptr inside =
      std::make_shared<mapnik::feature_impl>(
        std::make_shared<mapnik::context_type>(), feat->id());
    mapnik::feature_ptr outside =
      std::make_shared<mapnik::feature_impl>(
        std::make_shared<mapnik::context_type>(), feat->id());
    for (auto const &kv : *(feat->context())) {
      inside->put_new(kv.first, kv.second);
      outside->put_new(kv.first, kv.second);
    }

    for (auto const &geom : feat->paths()) {
      split(geom, e.polygon, inside, outside);
    }

    if (!inside->paths().empty()) {
      std::set<unsigned int> inside_indices(indices);
      inside_indices.insert(index);

      if (collect) {
        // if collecting, then we need to recurse, as later
        // polygons could add further parameter values.
        split_and_update(inside_indices, remaining_indices, collect,
                         entries, std::move(inside), param_name,
                         delimiter, append_to);

      } else {
        // if not collecting, then we have hit the first already
        // since we went through the indices in order, so there
        // is no need to recurse.
        update_feature_params(inside_indices, collect, entries,
                              std::move(inside), param_name,
                              delimiter, append_to);
      }
    }

    if (!outside->paths().empty()) {
      // always recurse on the outside, as we don't yet know the
      // relation between the geometries and the other admin
      // polygons.
      split_and_update(indices, remaining_indices, collect,
                       entries, std::move(outside), param_name,
                       delimiter, append_to);
    }
  }
}

/* the boost::geometry rtree index needs to be passed an iterator
 * which it will call with each value corresponding to an element
 * matching the query. we use the type below as a kind of back
 * inserter iterator, but only when the detailed geometry (rtree
 * stores only bboxes) matches the query geometry.
 */
template <typename GeomType>
struct intersects_iterator {
  const GeomType &m_geom;
  const std::vector<entry> &m_entries;
  param_updater &m_updater;

  intersects_iterator(const GeomType &geom,
                      const std::vector<entry> &entries,
                      param_updater &updater)
    : m_geom(geom), m_entries(entries), m_updater(updater) {
  }

  intersects_iterator &operator++() { // prefix
    return *this;
  }

  intersects_iterator &operator*() {
    return *this;
  }

  intersects_iterator &operator=(const value &v) {
    const entry &e = m_entries[v.second];

    // do detailed intersection test, as the index only does bounding
    // box intersection tests.
    if (intersects(e.polygon)) {
      m_updater(e);
    }

    return *this;
  }

  bool intersects(const polygon_2d &) const;
};

template <>
bool intersects_iterator<multi_point_2d>::intersects(const polygon_2d &poly) const {
  // TODO: remove this hack when/if bg::intersects supports
  // intersection on multi type.
  for (auto const &point : m_geom) {
    if (bg::intersects(point, poly)) {
      return true;
    }
  }
  return false;
}

template <>
bool intersects_iterator<multi_linestring_2d>::intersects(const polygon_2d &poly) const {
  // TODO: remove this hack when/if bg::intersects supports
  // intersection on multi type.
  for (auto const &line : m_geom) {
    if (bg::intersects(line, poly)) {
      return true;
    }
  }
  return false;
}

template <>
bool intersects_iterator<polygon_2d>::intersects(const polygon_2d &poly) const {
  return bg::intersects(m_geom, poly);
}

template <typename RTreeType, typename GeomType>
void try_update(RTreeType &index,
                const GeomType &geom,
                const std::vector<entry> &entries,
                param_updater &updater) {

  intersects_iterator<GeomType> itr(geom, entries, updater);
  index.query(bgi::intersects(bg::return_envelope<box_2d>(geom)), itr);
}

} // anonymous namespace

namespace avecado {
namespace post_process {

/* rtree index data structure from boost::geometry. this allows us
 * to query a set of polygons in logarithmic time rather than linear
 * for a sequential scan.
 *
 * note that the rtree is over `struct value`, which does not store
 * a polygon - it stores the polygon's bounding box and the index of
 * that polygon into the `entries` array. this means the rtree is
 * able to accelerate testing by culling intersections which are
 * impossible, but means we'll need to re-check that the geometries
 * actually intersect in a later pass.
 */
using rtree = bgi::rtree<value, bgi::quadratic<16> >;

/**
 * Post-process that applies administrative region attribution
 * to features, based on geographic location of the geometry.
 */
class adminizer : public izer {
public:
  adminizer(pt::ptree const& config);
  virtual ~adminizer();

  virtual void process(std::vector<mapnik::feature_ptr> &layer, mapnik::Map const& map) const;

private:
  std::vector<entry> make_entries(const mapnik::box2d<double> &env) const;
  rtree make_index(const std::vector<entry> &entries) const;
  void adminize_feature(mapnik::feature_ptr &&f,
                        const rtree &index,
                        const std::vector<entry> &entries,
                        std::vector<mapnik::feature_ptr> &append_to) const;

  // the name of the parameter to take from the admin polygon and set
  // on the feature being adminized.
  std::string m_param_name;

  // if true, split geometries at admin polygon boundaries. if false,
  // do not modify the geometries.
  bool m_split;

  // if true, collect all matching admin parameters. if false, use the
  // first admin parameter only.
  bool m_collect;

  // string to use to separate parameter values when m_collect == true.
  mapnik::value_unicode_string m_delimiter;

  // data source to fetch matching admin boundaries from.
  std::shared_ptr<mapnik::datasource> m_datasource;
};

adminizer::adminizer(pt::ptree const& config)
  : m_param_name(config.get<std::string>("param_name"))
  , m_split(false)
  , m_collect(false)
  , m_delimiter(mapnik::value_unicode_string::fromUTF8(",")) {
  mapnik::parameters params;

  boost::optional<pt::ptree const &> datasource_config =
    config.get_child_optional("datasource");

  if (datasource_config) {
    for (auto &kv : *datasource_config) {
      params[kv.first] = kv.second.data();
    }
  }

  m_datasource = mapnik::datasource_cache::instance().create(params);

  boost::optional<std::string> split = config.get_optional<std::string>("split");
  if (split) {
    m_split = *split == "true";
  }

  boost::optional<std::string> collect = config.get_optional<std::string>("collect");
  if (collect) {
    m_collect = *collect == "true";
  }

  boost::optional<std::string> delimiter = config.get_optional<std::string>("delimiter");
  if (delimiter) {
    m_delimiter = mapnik::value_unicode_string::fromUTF8(*delimiter);
  }
}

adminizer::~adminizer() {
}

std::vector<entry> adminizer::make_entries(const mapnik::box2d<double> &env) const {
  // query the datasource
  // TODO: do we want to pass more things like scale denominator
  // and resolution type?
  mapnik::featureset_ptr fset = m_datasource->features(mapnik::query(env));

  std::vector<entry> entries;
  unsigned int index = 0;

  mapnik::feature_ptr f;
  while (f = fset->next()) {
    mapnik::value param = f->get(m_param_name);

    for (auto const &geom : f->paths()) {
      // ignore all non-polygon types
      if (geom.type() == mapnik::geometry_type::types::Polygon) {
        entries.emplace_back(make_boost_polygon(geom), std::move(param), index++);
      }
    }
  }

  return entries;
}

/* creates an rtree (from boost::geometry) index over a set of bounding
 * boxes of admin polygons. the rtree cannot, itself, handle polygons
 * directly and so we store a tuple of the polygon bbox and its index
 * into the `entries` vector so that we can retrieve the polygon (and
 * associated data in `struct entry`) and do more detailed intersection
 * checking.
 */
rtree adminizer::make_index(const std::vector<entry> &entries) const {
  // create envelope boxes for entries, as these are needed
  // up-front for the packing algorithm.
  std::vector<value> values;
  values.reserve(entries.size());
  const size_t num_entries = entries.size();
  for (size_t i = 0; i < num_entries; ++i) {
    values.emplace_back(bg::return_envelope<box_2d>(entries[i].polygon), i);
  }

  // construct index using packing algorithm, which leads to
  // better distribution for querying, but needs to be
  // instantiated with an iterator range.
  return rtree(values.begin(), values.end());
}

void adminizer::adminize_feature(mapnik::feature_ptr &&f,
                                 const rtree &index,
                                 const std::vector<entry> &entries,
                                 std::vector<mapnik::feature_ptr> &append_to) const {
  // param updater collects the indices (into `entries`) of the
  // polygons which intersect the features' geometries, which
  // will be used to update the parameters in the feature.
  param_updater updater(m_collect);

  for (auto const &geom : f->paths()) {
    if (geom.type() == mapnik::geometry_type::types::Point) {
      multi_point_2d multi_point = make_boost_point(geom);
      try_update(index, multi_point, entries, updater);

    } else if (geom.type() == mapnik::geometry_type::types::LineString) {
      multi_linestring_2d multi_line = make_boost_linestring(geom);
      try_update(index, multi_line, entries, updater);

    } else if (geom.type() == mapnik::geometry_type::types::Polygon) {
      polygon_2d poly = make_boost_polygon(geom);
      try_update(index, poly, entries, updater);
    }

    // quick exit the loop if there's nothing more to do.
    if (updater.m_finished) { break; }
  }

  if (m_split) {
    // if splitting, then start the recursive algorithm to cover all
    // relevant combinations of geometry and admin polygons
    // inside/outside regions.
    priority_queue remaining_indices(
      updater.m_indices.begin(), updater.m_indices.end());
    std::set<unsigned int> empty;

    split_and_update(empty, remaining_indices, m_collect, entries,
                     std::move(f), m_param_name, m_delimiter, append_to);

  } else {
    // if not splitting mode, then update the feature's parameters if it
    // intersected and add it to append_to.
    update_feature_params(updater, entries, std::move(f), m_param_name,
                          m_delimiter, append_to);
  }
}

void adminizer::process(std::vector<mapnik::feature_ptr> &layer, mapnik::Map const& map) const {
  // build extent of all features in layer
  mapnik::box2d<double> env = envelope(layer);

  // construct an index over the bounding boxes of the geometry,
  // first extracting the geometries from mapnik's representation
  // and transforming them too boost::geometry's representation.
  std::vector<entry> entries = make_entries(env);

  rtree index = make_index(entries);

  // loop over features, finding which items from the datasource
  // they intersect with.
  std::vector<mapnik::feature_ptr> new_features;
  for (mapnik::feature_ptr &f : layer) {
    adminize_feature(std::move(f), index, entries, new_features);
  }

  // move new features into the same array that we were passed.
  // this is so that we can add new features (e.g: when split).
  layer.clear();
  layer.swap(new_features);
}

izer_ptr create_adminizer(pt::ptree const& config) {
  return std::make_shared<adminizer>(config);
}

} // namespace post_process
} // namespace avecado


// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// Use, modification and distribution is subject to 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)
//
// Linestring Polygon Overlay Example

// NOTE: this example is obsolete. Boost.Geometry can now
// overlay linestrings/polygons.
// This sample will be removed in next version.

#include <fstream>
#include <iostream>
#include <string>
#include <vector>

#include <boost/foreach.hpp>

#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/c_array.hpp>

#if defined(HAVE_SVG)
#  include <boost/geometry/io/svg/svg_mapper.hpp>
#endif

BOOST_GEOMETRY_REGISTER_C_ARRAY_CS(cs::cartesian);

int main(void)
{
    namespace bg = boost::geometry;

    typedef bg::model::d2::point_xy<double> point_2d;

    bg::model::linestring<point_2d> ls;
    {
        const double c[][2] = { {0, 1}, {2, 5}, {5, 3} };
        bg::assign_points(ls, c);
    }

    bg::model::polygon<point_2d> p;
    {
        const double c[][2] = { {3, 0}, {0, 3}, {4, 5}, {3, 0} };
        bg::assign_points(p, c);
    }
    bg::correct(p);

#if defined(HAVE_SVG)
    // Create SVG-mapper
    std::ofstream stream("05_b_overlay_linestring_polygon_example.svg");
    bg::svg_mapper<point_2d> svg(stream, 500, 500);
    // Determine extend by adding geometries
    svg.add(p);
    svg.add(ls);
    // Map geometries
    svg.map(ls, "opacity:0.6;stroke:rgb(255,0,0);stroke-width:2;");
    svg.map(p, "opacity:0.6;fill:rgb(0,0,255);");
#endif

    // Calculate intersection points (turn points)
    typedef bg::detail::segment_ratio_type<point_2d, bg::detail::no_rescale_policy>::type segment_ratio;
    typedef bg::detail::overlay::turn_info<point_2d, segment_ratio> turn_info;
    std::vector<turn_info> turns;
    bg::detail::get_turns::no_interrupt_policy policy;
    bg::detail::no_rescale_policy rescale_policy;
    bg::strategy::intersection::services::default_strategy<typename bg::cs_tag<point_2d>::type>::type intersection_strategy;
    bg::get_turns<false, false, bg::detail::overlay::assign_null_policy>(ls, p, intersection_strategy, rescale_policy, turns, policy);

    std::cout << "Intersection of linestring/polygon" << std::endl;
    BOOST_FOREACH(turn_info const& turn, turns)
    {
        std::string action = "intersecting";
        if (turn.operations[0].operation
                == bg::detail::overlay::operation_intersection)
        {
            action = "entering";
        }
        else if (turn.operations[0].operation
                == bg::detail::overlay::operation_union)
        {
            action = "leaving";

        }
        std::cout << action << " polygon at " << bg::dsv(turn.point) << std::endl;
#if defined(HAVE_SVG)
        svg.map(turn.point, "fill:rgb(255,128,0);stroke:rgb(0,0,100);stroke-width:1");
        svg.text(turn.point, action, "fill:rgb(0,0,0);font-family:Arial;font-size:10px");
#endif
    }

    return 0;
}


//
//  SASLMechanism_DIGEST_MD5.cpp
//  DXMPP
//
//  Created by Stefan Karlsson 2014
//  Copyright (c) 2014 Deus ex Machinae. All rights reserved.
//

#include <DXMPP/SASL/SASLMechanism_DIGEST_MD5.hpp>
#include <pugixml/pugixml.hpp>
#include <DXMPP/JID.hpp>

#include <boost/function.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/thread.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/array.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1

#include <cryptopp/cryptlib.h>
#include <cryptopp/hex.h>
#include <cryptopp/md5.h>
#include <cryptopp/hmac.h>
#include <cryptopp/sha.h>
#include <cryptopp/base64.h>
#include <cryptopp/queue.h>

#include <sstream>
#include <ostream>
#include <iostream>

#include "SaslChallengeParser.hpp"

#include "CryptoPP_byte.hpp"

namespace DXMPP
{
    namespace SASL
    {
        using namespace std;
        using namespace pugi;

        namespace Weak
        {
            void SASL_Mechanism_DigestMD5::Begin()
            {
                //ChosenSASLMechanism = SASLMechanisms::DIGEST_MD5;
                string AuthXML ="<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>";
                Uplink->WriteTextToSocket(AuthXML);
            }

            string SASL_Mechanism_DigestMD5::GetMD5Hex(string Input)
            {
                CryptoPP::Weak::MD5 hash;
                CryptoPP::byte digest[ CryptoPP::Weak::MD5::DIGESTSIZE ];
                int length =CryptoPP::Weak::MD5::DIGESTSIZE;

                CryptoPP::HexEncoder Hexit;
                std::string TOutput;
                Hexit.Attach( new CryptoPP::StringSink( TOutput ) );

                hash.CalculateDigest( digest,
                                      reinterpret_cast<const unsigned char *>( Input.c_str() ),
                                      Input.length() );
                Hexit.Put( digest, length );
                Hexit.MessageEnd();

                boost::algorithm::to_lower(TOutput);
                return TOutput;
            }

            string SASL_Mechanism_DigestMD5::GetHA1(string X, string nonce, string cnonce)
            {
                CryptoPP::Weak::MD5 hash;
                CryptoPP::byte digest[ CryptoPP::Weak::MD5::DIGESTSIZE ];
                int digestlength =CryptoPP::Weak::MD5::DIGESTSIZE;

                // Calculatey Y
                hash.CalculateDigest( digest,
                                      reinterpret_cast<const unsigned char *>( X.c_str() ),
                                      X.length() );
                // X is now in digest

                stringstream TStream;
                TStream << ":" << nonce << ":" << cnonce;
                string AuthentiationDetails = TStream.str();
                int TLen = (int)digestlength + (int)AuthentiationDetails.length();
                CryptoPP::byte *T = new CryptoPP::byte[TLen];
                memcpy(T, digest, digestlength);
                memcpy(T+digestlength, AuthentiationDetails.c_str(), AuthentiationDetails.length());
                hash.CalculateDigest( digest, reinterpret_cast<const unsigned char *>( T ), TLen );

                CryptoPP::HexEncoder Hexit;
                std::string TOutput;
                Hexit.Attach( new CryptoPP::StringSink( TOutput ) );

                Hexit.Put( digest, digestlength );
                Hexit.MessageEnd();

                boost::algorithm::to_lower(TOutput);
                return TOutput;
            }

            void SASL_Mechanism_DigestMD5::Challenge(const pugi::xpath_node &challenge)
            {
                string ChallengeBase64 = challenge.node().child_value();
                string DecodedChallenge = DecodeBase64(ChallengeBase64);

                //std::cout << "GOT CHALLENGE " << ChallengeBase64 << " decoded as " <<  DecodedChallenge << std::endl;

                std::map<std::string,std::string> ChallengeMap; // its like a map to teh challengeh

                if(!ParseSASLChallenge(DecodedChallenge, ChallengeMap))
                    throw runtime_error("DXMPP: Failed to parse SASL Challenge.");

                string nonce = ChallengeMap["nonce"];
                string qop = ChallengeMap["qop"];
                string cnonce = boost::lexical_cast<string>( boost::uuids::random_generator()() );

                string rspauth = "";
                if(ChallengeMap.find("rspauth") != ChallengeMap.end())
                    rspauth = ChallengeMap["rspauth"];

                if(ChallengeMap.find("cnonce") != ChallengeMap.end())
                    cnonce = ChallengeMap["cnonce"];

                string realm = "";// MyJID.GetDomain();
                if(ChallengeMap.find("realm") != ChallengeMap.end())
                    realm = ChallengeMap["realm"];

                std::string authid = MyJID.GetUsername();
                std::string authzid = MyJID.GetFullJID();
                string nc = "00000001";

                if(!rspauth.empty())
                {
                    Uplink->WriteTextToSocket("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
                    return;
                }

                //cnonce= "lWThUe35I/Mykro89Cg44aks8HUCi2w0mfdrjdiz"; // hack

                //std::cout << "SASL Mechanism = DIGEST_MD5" << std::endl;

                stringstream TStream;
                std::string TOutput;

                // X
                TStream << MyJID.GetUsername() << ':' << realm << ':' << Password;
                string X = TStream.str();
                TStream.str("");
                TStream << "AUTHENTICATE:xmpp/" << MyJID.GetDomain();
                string A2 = TStream.str();

                string HA1 = GetHA1(X, nonce, cnonce);
                string HA2 = GetMD5Hex(A2);

                TStream.str("");
                TStream << HA1
                        << ':'
                        << nonce
                        << ':'
                        << nc
                        << ':'
                        << cnonce
                        << ':'
                        << qop
                        << ':'
                        << HA2;
                string KD = TStream.str();

                string Z = GetMD5Hex(KD);

                TStream.str("");

                TStream << "username=\""
                        << MyJID.GetUsername() << "\""
                //<< ",realm=\"" << realm << "\""
                        << ",nonce=\"" << nonce << "\""
                        << ",cnonce=\"" << cnonce << "\""
                        << ",nc=" << nc
                        << ",qop=auth,digest-uri=\"xmpp/"
                        << MyJID.GetDomain()<< "\""
                        << ",response="
                        << Z
                        << ",charset=utf-8";//,authzid=\"" << MyJID.GetFullJID() << "\"";

                string Response = TStream.str();
                Response = EncodeBase64(Response);

                TStream.str("");
                TStream << "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
                        << Response
                        << "</response>";

                string ResponseXML = TStream.str();

                Uplink->WriteTextToSocket(ResponseXML);
            }

            bool SASL_Mechanism_DigestMD5::Verify(const pugi::xpath_node &SuccessTag)
            {
                return true;
            }
        }
    }
}


//#############################################################################
                                 /*-:::--.`
                            -+shmMMNmmddmmNMNmho/.
                 `yyo++osddMms:                  `/yNNy-
              yo    +mMy:                       `./dMMdyssssso-
              oy  -dMy.                     `-+ssso:.`:mMy`   .ys
                ho+MN:                  `:osso/.         oMm-   +h
                +Mmd-           `/syo-                     :MNhs`
                `NM-.hs`      :syo:                          sMh
                oMh   :ho``/yy+.                             `MM.
                hM+    `yNN/`                                 dM+
                dM/  -sy/`/ho`                                hMo
                hMo/ho.     :yy-                             dM/
            :dNM/             :yy:                         yMy
            sy`:MN.              `+ys-                     +Mm`
            oy`   :NM+                  .+ys/`           `hMd.ys
            /sssssyNMm:                   `:sys:`     `oNN+   m-
                        .sNMh+.                   `:sNMdyysssssy:
                        -odMNhs+:-.`    `.-/oydMNh+.
                            `-+shdNMMMMMMMNmdyo/.
                                    `````*/
//#############################################################################
// Thread to render using libIGL
//#############################################################################

#include "visualizer.h"
#include "visualizer_ui.h"

#include <igl/fit_plane.h>

#include "algebra/plane.h"

// Static opengl window where we render our results on libigl
igl::opengl::glfw::Viewer viewer;

// Viewer thread, we try to lock as less as we can.
// This thread contains our UI and displays and should only be locked to update
// the render objects.

er::worker_t viewer_thread;

//#############################################################################
// Utils
//#############################################################################

//#############################################################################
// Pushed point cloud from the realsense Thread
//#############################################################################

er::frame_data::frame_data() : f_external_render { nullptr }, initialized { false },
visible { true }, idx { 0 }, invalidate { false }, point_scale { 0 }
{
	cloud = pcl_ptr(new pcl::PointCloud<pcl::PointXYZRGBA>);
}

void er::frame_data::calculate_view()
{
	std::lock_guard<std::mutex> lock(mtx);
	size_t size = cloud->points.size();

	V.resize(size, 3);
	C.resize(size, 3);

	int i = 0;
	for (auto& p : cloud->points) {

		//printf(" %2.2f, %2.2f, %2.2f ", p.x, p.y, p.z);
		V(i, 0) = p.x;
		V(i, 1) = p.y;
		V(i, 2) = p.z;

		C(i, 0) = p.r / 255.f;
		C(i, 1) = p.g / 255.f;
		C(i, 2) = p.b / 255.f;
		i++;
	}

	radius.resize(size);
	radius.setConstant(er::app_state::get().point_scale + point_scale);

	bbx_m = V.colwise().minCoeff();
	bbx_M = V.colwise().maxCoeff();
}

void er::frame_data::render(void *viewer_ptr)
{
#ifdef USE_IMGUI
	if (!visible)
		return;

	std::lock_guard<std::mutex> lock(mtx);
	igl::opengl::glfw::Viewer *viewer = (igl::opengl::glfw::Viewer *) viewer_ptr;

#ifdef USE_POINT_SIZE
	viewer->data().set_points(V, C, radius);
#else
	viewer->data().set_points(V, C);
#endif

	id_mesh = viewer->data().id;
	viewer->append_mesh();

	//-------------------------------------------------------------------------
	// Find the bounding box
	if (er::app_state::get().show_bbx) {

		// Corners of the bounding box
		Eigen::MatrixXd V_box(8, 3);
		V_box <<
			bbx_m(0), bbx_m(1), bbx_m(2),
			bbx_M(0), bbx_m(1), bbx_m(2),
			bbx_M(0), bbx_M(1), bbx_m(2),
			bbx_m(0), bbx_M(1), bbx_m(2),
			bbx_m(0), bbx_m(1), bbx_M(2),
			bbx_M(0), bbx_m(1), bbx_M(2),
			bbx_M(0), bbx_M(1), bbx_M(2),
			bbx_m(0), bbx_M(1), bbx_M(2);

		// Edges of the bounding box
		Eigen::MatrixXi E_box(12, 2);
		E_box << 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 7, 3;

		Eigen::VectorXd radius_(V_box.rows());
		radius.setConstant(er::app_state::get().point_scale);

		// Plot labels with the coordinates of bounding box vertices
		std::stringstream l1;
		l1 << bbx_m(0) << ", " << bbx_m(1) << ", " << bbx_m(2);
		viewer->data().add_label(bbx_m, l1.str());
		std::stringstream l2;
		l2 << bbx_M(0) << ", " << bbx_M(1) << ", " << bbx_M(2);
		viewer->data().add_label(bbx_M, l2.str());
	}

	for (er::frame_data *sub_view : sub_views) {
		sub_view->render(viewer_ptr);
	}

	if (f_external_render != nullptr) {
		f_external_render(viewer_ptr);
	}
#endif
}

void er::frame_data::invalidate_cloud(pcl_ptr cloud_)
{
	invalidate = true;
	pcl::copyPointCloud(*cloud_, *cloud);

	size_t size = cloud->points.size();
	if (size == 0)
		return;

	calculate_view();
}

void er::frame_data::render_text(void *viewer_ptr, Eigen::RowVector3d &cp,
	const char *text)
{
	if (viewer_ptr == nullptr)
		return;

	igl::opengl::glfw::Viewer *viewer = (igl::opengl::glfw::Viewer *) viewer_ptr;
	viewer->data().add_label(cp, text);
}

// Helper to render a plane
void er::frame_data::render_point(void *viewer_ptr,
	Eigen::RowVector3d &cp,
	Eigen::Vector3d &color,
	const char *text)
{
	if (viewer_ptr == nullptr)
		return;

	igl::opengl::glfw::Viewer *viewer = (igl::opengl::glfw::Viewer *) viewer_ptr;

	if (text != nullptr)
		viewer->data().add_label(cp, text);

	Eigen::MatrixXd V(1, 3);
	V << cp[0], cp[1], cp[2];

	Eigen::MatrixXd C(1, 3);
	C << color[0], color[1], color[2];

#ifdef USE_POINT_SIZE
	Eigen::VectorXd radius(1);
	radius.setConstant(er::app_state::get().point_scale * 10.5);

	viewer->data().set_points(V, C, radius);
#else
	viewer->data().set_points(V, C);
#endif

	viewer->append_mesh();
}

// Helper to render a plane
void er::frame_data::render_plane(void *viewer_ptr,
	plane &p,
	Eigen::Vector3d &m,
	Eigen::Vector3d &M)
{
	if (viewer_ptr == nullptr)
		return;

	igl::opengl::glfw::Viewer *viewer = (igl::opengl::glfw::Viewer *) viewer_ptr;
	Eigen::MatrixXd V(4, 3);
	V <<
		m(0), p.get_y(m(0), m(2)), m(2),
		M(0), p.get_y(M(0), m(2)), m(2),
		m(0), p.get_y(m(0), M(2)), M(2),
		M(0), p.get_y(M(0), M(2)), M(2);

	if (er::app_state::get().bool_debug_verbose) {
		std::cout << "-- Render Plane --" << std::endl;
		std::cout << V << std::endl;
	}

	Eigen::MatrixXi F(2, 3);
	F <<
		0, 1, 2,
		1, 2, 3;

	Eigen::MatrixXd C;
	C.resize(4, 3);

	Eigen::VectorXd Z = V.col(2);
	igl::jet(Z, true, C);

	viewer->data().set_mesh(V, F);
	viewer->data().set_colors(C);

	viewer->append_mesh();
}

//----------------------------------------------------------------------------

void er::worker_t::setup()
{
	bthread = new boost::thread(boost::bind(&er::worker_t::start, this));
}

void er::worker_t::add_axis()
{
	Eigen::MatrixXd V_axis(4, 3);
	V_axis <<
		0, 0, 0,
		1, 0, 0,
		0, 1, 0,
		0, 0, 1;

	Eigen::MatrixXi E_axis(3, 2);
	E_axis << 0, 1, 0, 2, 0, 3;

#ifdef USE_POINT_SIZE
	Eigen::VectorXd radius(V_axis.rows());
	radius.setConstant(er::app_state::get().point_scale * 2.5 * viewer.core.camera_base_zoom);

	// Plot the corners of the bounding box as points
	viewer.data().add_points(V_axis, Eigen::RowVector3d(1, 0, 0), radius);
#else
	viewer.data().add_points(V_axis, Eigen::RowVector3d(1, 0, 0));
#endif

	// Plot labels with the coordinates of bounding box vertices
	Eigen::Vector3d x(1, 0, 0);
	viewer.data().add_label(x, "x");

	Eigen::Vector3d y(0, 1, 0);
	viewer.data().add_label(y, "y");

	Eigen::Vector3d z(0, 0, 1);
	viewer.data().add_label(z, "z");

	Eigen::Vector3d centre(0, 0, 0);
	viewer.data().add_label(centre, "centre");

	viewer.append_mesh();
	axis_index = viewer.selected_data_index;
}

void er::worker_t::test_cube()
{
	Eigen::MatrixXd V(8, 3);
	V <<
		0.0, 0.0, 0.0,
		0.0, 0.0, 1.0,
		0.0, 1.0, 0.0,
		0.0, 1.0, 1.0,
		1.0, 0.0, 0.0,
		1.0, 0.0, 1.0,
		1.0, 1.0, 0.0,
		1.0, 1.0, 1.0;
	Eigen::MatrixXi F(12, 3);
	F <<
		0, 6, 4,
		0, 2, 6,
		0, 3, 2,
		0, 1, 3,
		2, 7, 6,
		2, 3, 7,
		4, 6, 7,
		4, 7, 5,
		0, 4, 5,
		0, 5, 1,
		1, 5, 7,
		1, 7, 3;

	viewer.data().set_mesh(V, F);
	viewer.append_mesh();
}

void er::worker_t::compute_cloud()
{
	if (!initialized)
		return;

	if (!update_view)
		return;

	while (viewer.selected_data_index != axis_index) {
		viewer.erase_mesh(viewer.selected_data_index);
	}

	viewer.data().clear();

	for (auto &data : data_views) {
		data->render((void *) &viewer);
	}

	update_view = false;
}

#include <Eigen/Geometry>

//-----------------------------------------------------------------------------
// Random code testing
//-----------------------------------------------------------------------------

void testing()
{
	Eigen::MatrixXd V_test;
	V_test.resize(2, 3);
	V_test << 0, 0, 0,
		0, 1, 0;

	using namespace std;
	using namespace Eigen;

	cout << V_test << endl;

	Tform3 T;
	T = Tform3::Identity();
	cout << "T = Tform3::Identity();" << endl;
	cout << "T=[" << endl << T.affine().matrix() << endl << "];" << endl;
	cout << "T.translate(Vec3(1,2,3));" << endl;
	T.translate(Vec3(1, 2, 3));
	cout << "T=[" << endl << T.affine().matrix() << endl << "];" << endl;

	for (int r = 0; r < V_test.rows(); r++) {
		Vector3d v = V_test.row(r);
		v = T * v;
		V_test.row(r) = v;
	}

	cout << V_test << endl;
}

//-------------------------------------------------------------------------
void er::worker_t::start()
{
#ifdef USE_IMGUI
	printf("Start thread\n");

	// Load an example mesh in OFF format
	// Just to check that we are have a functional libIGL.

	// TODO: This thread will crash if the window is not created on time.
	boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));

	//------------------------------------------------------------
	// Just a basic testing Grid
	//

	{
		Eigen::MatrixXd V, C;
		Eigen::MatrixXi F;

#ifdef WIN32
		igl::readOBJ("S:/er_vision_pipeline/assets/floor.obj", V, F);
#else
		igl::readOBJ("../assets/floor.obj", V, F);
#endif

		Eigen::VectorXd radius(V.rows());
		radius.setConstant(0.01 * viewer.core.camera_base_zoom);

		//Eigen::VectorXd Z = V.col(2);
		//igl::jet(Z, true, C);

		viewer.data().set_mesh(V, F);
		//viewer.data().set_colors(C);
		viewer.append_mesh();
	}

	//------------------------------------------------------------

	initialize_visualizer_ui(viewer);

	add_axis();

	viewer.callback_init = [&] (igl::opengl::glfw::Viewer &viewer_) {
		printf("Setting up camera!\n");

		// Position the camera in our reference frame
		viewer.core.camera_eye = Eigen::Vector3f(0, 1, -0.5f);
		viewer.core.is_animating = true;

		// Load camera position

		try {
			viewer.core.camera_translation = app_state::get().load_vec3f("camera_translation");
			Eigen::Vector4f v4 = app_state::get().load_vec4f("trackball_angle");
			viewer.core.trackball_angle = Eigen::Quaternionf(v4.w(), v4.x(), v4.y(), v4.z());
			viewer.core.camera_zoom = app_state::get().config["camera_zoom"];
		} catch (const std::exception &e) {
			printf(" No default config\n");
		}

		if (viewer.core.camera_zoom == 0) {
			printf(" No camera info, we should default to normal one");
			viewer.core.camera_zoom = 1.0f;
		}

		return false;
	};

	viewer.callback_pre_draw = [&] (igl::opengl::glfw::Viewer &viewer_) {
		return false;
	};

	// Thread were we check to see if we have to invalidate the pointcloud
	viewer.callback_post_draw = [&] (igl::opengl::glfw::Viewer &viewer_) {
		initialized = true;
		// Position the camera in our reference frame
		compute_cloud();
		return false;
	};

	viewer.core.viewport << 0, 0, 1800, 924;

	viewer.launch();
	printf("Closing down");
	er::app_state::get().should_close_app = true;
#endif
}

std::vector<er::frame_data *> &er::worker_t::get_data_views()
{
	return data_views;
}

er::worker_t *launch_visualizer()
{
	viewer_thread.setup();
	return &viewer_thread;
}


/**
 * @file barConnectionInfoTest.cpp
 * @author Luiz Victor Linhares Rocha (luizvictorlrocha@gmail.com)
 * @brief test the Pmu connection
 * @version 0.1
 * @date 2018-10-08
 *
 * @copyright Copyright (c) 2018
 *
 */

#define BOOST_TEST_DYN_LINK

#include <random>
#include <fstream>
#include <vector>
#include <boost/test/unit_test.hpp>
#include <boost/test/test_tools.hpp>
#include "../rede/neuralFluxDeclare.hpp"
#include "../rede/cdfReader.hpp"
#include "../rede/powerNet.hpp"
#include "../rede/pmuConnector.hpp"

using neuralFlux::BarConnectionInfoPtr;
using neuralFlux::PmuConnector;
using neuralFlux::CdfReader;
using std::ifstream;
using neuralFlux::PowerNetPtr;
using std::vector;

BOOST_AUTO_TEST_CASE(pmu_conn_test_constructor) {
    CdfReader reader;
    ifstream input("/home/luiz/projects/neuralPowerFlow/netData/ieee14cdf.txt");
    if (!input) {
        BOOST_TEST_FAIL("error in file");
    }
    PowerNetPtr net = reader.readNet(input);
    PmuConnector conn(net);
    PowerNetPtr net2 = conn.getNet();
    BOOST_TEST(net == net2);
}

BOOST_AUTO_TEST_CASE(pmu_conn_test_14) {
    CdfReader reader;
    ifstream input("/home/luiz/projects/neuralPowerFlow/netData/ieee14cdf.txt");
    if (!input) {
        BOOST_TEST_FAIL("error in file");
    }
    PowerNetPtr net = reader.readNet(input);
    PmuConnector conn(net);
    BOOST_TEST(net->getNBars() == 14);
    std::default_random_engine eng(0);
    vector<BarConnectionInfoPtr> connections = conn.insertPmus(&eng);
    int score = conn.getScore();
    BOOST_TEST(score == 2176);
}

BOOST_AUTO_TEST_CASE(pmu_conn_14) {
    CdfReader reader;
    ifstream input("/home/luiz/projects/neuralPowerFlow/netData/ieee14cdf.txt");
    if (!input) {
        BOOST_TEST_FAIL("error in file");
    }
    PowerNetPtr net = reader.readNet(input);
    PmuConnector conn(net);
    vector<int> answer = conn.insertBestPmusDeterministic();
    BOOST_TEST(answer.size() == 2);
}


//==================================================================================================
/*!
  @file

    @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_HMSB_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_HMSB_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{
  /*!
    @ingroup group-reduction

    Returns a bs::bitset build from the most significant bit of each value its
    argument.

    @par Header <boost/simd/function/hmsb.hpp>

    @par Example:

      @snippet hmsb.cpp hmsb

    @par Possible output:

      @snippet hmsb.txt hmsb

    @param  v Value to process
    @return A bitset-like structure of the size of cardinal(v) containing the most significant
            bits of each elements of v.
  **/
  bitset<cardinal_of<Value>::value> hmsb(Value const &v);
} }
#endif

#include <boost/simd/function/scalar/hmsb.hpp>
#include <boost/simd/function/simd/hmsb.hpp>

#endif


/*******************************************************************************
 *         Copyright 2003 & onward LASMEA UMR 6602 CNRS/Univ. Clermont II
 *         Copyright 2009 & onward LRI    UMR 8623 CNRS/Univ Paris Sud XI
 *
 *          Distributed under the Boost Software License, Version 1.0.
 *                 See accompanying file LICENSE.txt or copy at
 *                     http://www.boost.org/LICENSE_1_0.txt
 ******************************************************************************/
#ifndef NT2_SDK_MEMORY_META_IS_ALIGNED_HPP_INCLUDED
#define NT2_SDK_MEMORY_META_IS_ALIGNED_HPP_INCLUDED

#include <cstddef>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/size_t.hpp>
#include <nt2/sdk/memory/parameters.hpp>
#include <nt2/sdk/error/static_assert.hpp>
#include <nt2/sdk/memory/meta/is_power_of_2.hpp>

namespace nt2 { namespace meta
{
  //////////////////////////////////////////////////////////////////////////////
  // Boolean meta-function checking if a integral constant is aligned on a given
  // power of 2 boundary.
  // Documentation: reference/sdk/aligned/meta/is_aligned_c.rst
  //////////////////////////////////////////////////////////////////////////////
  template<std::size_t V, std::size_t N = NT2_CONFIG_ALIGNMENT>
  struct is_aligned_c : boost::mpl::bool_<!(V & (N-1) )>
  {
    NT2_STATIC_ASSERT ( (meta::is_power_of_2_c<N>::value)
                      , INVALID_ALIGNMENT_VALUE
                      , "Alignment detection done on a non-power of two boundary."
                      );
  };

  //////////////////////////////////////////////////////////////////////////////
  // Boolean meta-function checking if a Integral Constant is aligned on a given
  // power of 2 boundary.
  // Documentation: reference/sdk/aligned/meta/is_aligned.rst
  //////////////////////////////////////////////////////////////////////////////
  template<class V, class N = boost::mpl::size_t<NT2_CONFIG_ALIGNMENT> >
  struct is_aligned : is_aligned_c<V::value,N::value> {};

} }

#endif


//==================================================================================================
/*!

  Copyright 2015 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#include <boost/simd/constant/fifteen.hpp>
#include <boost/simd/as.hpp>
#include <stf.hpp>

STF_CASE_TPL( "Check fifteen behavior for integral types"
            , (std::uint8_t)(std::uint16_t)(std::uint32_t)(std::uint64_t)
              (std::int8_t)(std::int16_t)(std::int32_t)(std::int64_t)
            )
{
  using boost::simd::as;
  using boost::simd::detail::fifteen;
  using boost::simd::Fifteen;

  STF_TYPE_IS(decltype(Fifteen<T>()), T);
  STF_EQUAL(Fifteen<T>(), T(15));
  STF_EQUAL(fifteen( as(T{}) ),T(15));
}

STF_CASE_TPL( "Check fifteen behavior for floating types"
            , (double)(float)
            )
{
  using boost::simd::as;
  using boost::simd::detail::fifteen;
  using boost::simd::Fifteen;

  STF_TYPE_IS(decltype(Fifteen<T>()), T);
  STF_IEEE_EQUAL(Fifteen<T>(), T(15));
  STF_IEEE_EQUAL(fifteen( as(T{}) ), T(15));
}