// Boost.Geometry // Copyright (c) 2019-2020, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { // true for any geometry template struct is_geometry : boost::integral_constant < bool, (! boost::is_void::type>::value) > {}; // true for multi-point, multi-linestring or multi-polygon template struct is_multi_geometry : boost::is_base_of < geometry::multi_tag, typename geometry::tag::type > {}; // true for point, linestring or polygon template struct is_multi_geometry_element : boost::integral_constant < bool, ((boost::is_same::type, point_tag>::value) || (boost::is_same::type, linestring_tag>::value) || (boost::is_same::type, polygon_tag>::value)) > {}; template struct is_range_impl { typedef boost::type_traits::yes_type yes_type; typedef boost::type_traits::no_type no_type; template static yes_type test(typename boost::range_iterator::type*); template static no_type test(...); static const bool value = (sizeof(test(0)) == sizeof(yes_type)); }; // true if T is range (boost::range_iterator::type is defined) template struct is_range : boost::integral_constant::value> {}; template ::value> struct is_tupled_output_element_base : boost::integral_constant {}; template struct is_tupled_output_element_base : boost::integral_constant < bool, (is_multi_geometry::value || ((! is_geometry::value) && is_multi_geometry_element < typename boost::range_value::type >::value)) > {}; // true if T is a multi-geometry or is a range of points, linestrings or // polygons template struct is_tupled_output_element : is_tupled_output_element_base {}; // true if Output is not a geometry (so e.g. tuple was not adapted to any // concept) and at least one of the tuple elements is a multi-geometry or // a range of points, linestrings or polygons template struct is_tupled_output_check : boost::mpl::and_ < boost::is_same::type, void>, //geometry::tuples::exists_if geometry::tuples::exists_if > {}; // true if T is not a geometry (so e.g. tuple was not adapted to any // concept) and at least one of the tuple elements is a point, linesting // or polygon template struct is_tupled_single_output_check : boost::mpl::and_ < boost::is_same::type, void>, geometry::tuples::exists_if > {}; // true if Output is boost::tuple, boost::tuples::cons, std::pair or std::tuple template struct is_tupled : boost::integral_constant {}; template < class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9 > struct is_tupled > : boost::integral_constant {}; template struct is_tupled > : boost::integral_constant {}; template struct is_tupled > : boost::integral_constant {}; #ifdef BOOST_GEOMETRY_CXX11_TUPLE template struct is_tupled > : boost::integral_constant {}; #endif // BOOST_GEOMETRY_CXX11_TUPLE // true if Output is boost::tuple, boost::tuples::cons, std::pair or std::tuple // and is_tupled_output_check defiend above passes template ::value> struct is_tupled_output : boost::integral_constant {}; template struct is_tupled_output : is_tupled_output_check {}; // true if T is boost::tuple, boost::tuples::cons, std::pair or std::tuple // and is_tupled_single_output_check defiend above passes template ::value> struct is_tupled_single_output : boost::integral_constant {}; template struct is_tupled_single_output : is_tupled_single_output_check {}; template struct tupled_output_find_index_pred { template struct pred : boost::is_same::type, Tag> {}; }; // Valid only if tupled_output_has is true template struct tupled_output_find_index : geometry::tuples::find_index_if < Output, tupled_output_find_index_pred::template pred > {}; template < typename Output, typename Tag, bool IsTupledOutput = is_tupled_output::value > struct tupled_output_has : boost::integral_constant {}; template struct tupled_output_has : boost::integral_constant < bool, ((tupled_output_find_index::value) < (geometry::tuples::size::value)) > {}; // Valid only if tupled_output_has is true template inline typename geometry::tuples::element < tupled_output_find_index::value, Output >::type & tupled_output_get(Output & output) { return geometry::tuples::get::value>(output); } // defines a tuple-type holding value-types of ranges being elements of // Output pair/tuple template < typename Tuple, size_t I = 0, size_t N = geometry::tuples::size::value > struct tupled_range_values_bt { typedef boost::tuples::cons < typename boost::range_value < typename geometry::tuples::element::type >::type, typename tupled_range_values_bt::type > type; }; template struct tupled_range_values_bt { typedef boost::tuples::null_type type; }; template struct tupled_range_values : tupled_range_values_bt {}; template struct tupled_range_values > { typedef std::pair < typename boost::range_value::type, typename boost::range_value::type > type; }; #ifdef BOOST_GEOMETRY_CXX11_TUPLE template struct tupled_range_values > { typedef std::tuple::type...> type; }; #endif // BOOST_GEOMETRY_CXX11_TUPLE // util defining a type and creating a tuple holding back-insert-iterators to // ranges being elements of Output pair/tuple template ::value> struct tupled_back_inserters_bt { typedef boost::tuples::cons < geometry::range::back_insert_iterator < typename geometry::tuples::element::type >, typename tupled_back_inserters_bt::type > type; static type apply(Tuple & tup) { return type(geometry::range::back_inserter(geometry::tuples::get(tup)), tupled_back_inserters_bt::apply(tup)); } }; template struct tupled_back_inserters_bt { typedef boost::tuples::null_type type; static type apply(Tuple const&) { return type(); } }; template struct tupled_back_inserters : tupled_back_inserters_bt {}; template struct tupled_back_inserters > { typedef std::pair < geometry::range::back_insert_iterator, geometry::range::back_insert_iterator > type; static type apply(std::pair & p) { return type(geometry::range::back_inserter(p.first), geometry::range::back_inserter(p.second)); } }; #ifdef BOOST_GEOMETRY_CXX11_TUPLE // NOTE: In C++14 std::integer_sequence and std::make_integer_sequence could be used template struct tupled_back_inserters_st; template struct tupled_back_inserters_st, std::tuple > { typedef std::tuple...> type; static type apply(std::tuple & tup) { return type(geometry::range::back_inserter(std::get(tup))...); } }; template struct tupled_back_inserters > : tupled_back_inserters_st < typename geometry::tuples::make_int_sequence::type, std::tuple > {}; #endif // BOOST_GEOMETRY_CXX11_TUPLE template < typename GeometryOut, bool IsTupled = is_tupled_output::value > struct output_geometry_value : boost::range_value {}; template struct output_geometry_value : tupled_range_values {}; template < typename GeometryOut, bool IsTupled = is_tupled_output::value > struct output_geometry_back_inserter_ { typedef geometry::range::back_insert_iterator type; static type apply(GeometryOut & out) { return geometry::range::back_inserter(out); } }; template struct output_geometry_back_inserter_ : tupled_back_inserters {}; template inline typename output_geometry_back_inserter_::type output_geometry_back_inserter(GeometryOut & out) { return output_geometry_back_inserter_::apply(out); } // is_tag_same_as_pred // Defines a predicate true if type's tag is the same as Tag template struct is_tag_same_as_pred { template struct pred : boost::is_same::type, Tag> {}; }; // Allows to access a type/object in a pair/tuple corresponding to an index in // GeometryOut pair/tuple of a geometry defined by Tag. // If GeometryOut is a geometry then it's expected to be defined by DefaultTag. template < typename GeometryOut, typename Tag, typename DefaultTag, typename GeometryTag = typename geometry::tag::type > struct output_geometry_access {}; // assume GeometryTag is void because not adapted tuple holding geometries was passed template struct output_geometry_access { static const int index = geometry::tuples::find_index_if < TupledOut, is_tag_same_as_pred::template pred >::value; typedef typename geometry::tuples::element::type type; template static typename geometry::tuples::element::type& get(Tuple & tup) { return geometry::tuples::get(tup); } }; template struct output_geometry_access { typedef GeometryOut type; template static T& get(T & v) { return v; } }; template struct output_geometry_concept_check { static void apply() { concepts::check(); } }; template struct output_geometry_concept_check > { static void apply() { concepts::check(); concepts::check(); } }; template ::value> struct output_geometry_concept_check_t { static void apply() { concepts::check::type>(); output_geometry_concept_check_t::apply(); } }; template struct output_geometry_concept_check_t { static void apply() {} }; template < class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9 > struct output_geometry_concept_check > : output_geometry_concept_check_t > {}; template struct output_geometry_concept_check > : output_geometry_concept_check_t > {}; #ifdef BOOST_GEOMETRY_CXX11_TUPLE template struct output_geometry_concept_check > : output_geometry_concept_check_t > {}; #endif // BOOST_GEOMETRY_CXX11_TUPLE struct tupled_output_tag {}; template struct setop_insert_output_tag : boost::mpl::if_c < geometry::detail::is_tupled_single_output::value, tupled_output_tag, typename geometry::tag::type > {}; template struct expect_output_assert_base; template struct expect_output_assert_base { BOOST_MPL_ASSERT_MSG ( IsFound, POINTLIKE_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT, (types) ); }; template struct expect_output_assert_base { BOOST_MPL_ASSERT_MSG ( IsFound, LINEAR_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT, (types) ); }; template struct expect_output_assert_base { BOOST_MPL_ASSERT_MSG ( IsFound, AREAL_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT, (types) ); }; template struct expect_output_assert : expect_output_assert_base < Geometry1, Geometry2, TupledOut, geometry::tuples::exists_if < TupledOut, is_tag_same_as_pred::template pred >::value, typename geometry::tag_cast < Tag, pointlike_tag, linear_tag, areal_tag >::type > {}; template struct expect_output_assert {}; template < typename Geometry1, typename Geometry2, typename TupledOut, typename Tag1, typename Tag2 = void, typename Tag3 = void > struct expect_output : expect_output_assert , expect_output_assert , expect_output_assert {}; template < typename Geometry1, typename Geometry2, typename TupledOut, typename Tag1, typename Tag2 > struct expect_output : expect_output_assert , expect_output_assert {}; template < typename Geometry1, typename Geometry2, typename TupledOut, typename Tag1 > struct expect_output : expect_output_assert {}; template struct single_tag_from_base_tag; template <> struct single_tag_from_base_tag { typedef point_tag type; }; template <> struct single_tag_from_base_tag { typedef linestring_tag type; }; template <> struct single_tag_from_base_tag { typedef polygon_tag type; }; template < typename Geometry, typename SingleOut, bool IsMulti = geometry::detail::is_multi_geometry::value > struct convert_to_output { template static OutputIterator apply(Geometry const& geometry, OutputIterator oit) { SingleOut single_out; geometry::convert(geometry, single_out); *oit++ = single_out; return oit; } }; template < typename Geometry, typename SingleOut > struct convert_to_output { template static OutputIterator apply(Geometry const& geometry, OutputIterator oit) { typedef typename boost::range_iterator::type iterator; for (iterator it = boost::begin(geometry); it != boost::end(geometry); ++it) { SingleOut single_out; geometry::convert(*it, single_out); *oit++ = single_out; } return oit; } }; } // namespace detail #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP