// 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 namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { template ::value> struct is_tupled_output_element_base : util::bool_constant {}; template struct is_tupled_output_element_base : util::bool_constant < (util::is_multi::value || (util::is_not_geometry::value && util::is_multi_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 : util::bool_constant < (util::is_not_geometry::value && geometry::tuples::exists_if::value) > {}; // 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 : util::bool_constant < (util::is_not_geometry::value && geometry::tuples::exists_if::value) > {}; // 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 : util::bool_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 : util::bool_constant {}; template struct is_tupled_single_output : is_tupled_single_output_check {}; template struct tupled_output_find_index_pred { template struct pred : std::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 : util::bool_constant {}; template struct tupled_output_has : util::bool_constant < ((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 struct tupled_range_values; template struct tupled_range_values > { typedef std::tuple::type...> type; }; template struct tupled_range_values > { typedef std::pair < typename boost::range_value::type, typename boost::range_value::type > type; }; template < typename Tuple, size_t I = 0, size_t N = boost::tuples::length::value > struct tupled_range_values_bt { typedef boost::tuples::cons < typename boost::range_value < typename boost::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> : tupled_range_values_bt> {}; // util defining a type and creating a tuple holding back-insert-iterators to // ranges being elements of Output pair/tuple template struct tupled_back_inserters; 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 < std::make_index_sequence, std::tuple > {}; 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)); } }; template ::value> struct tupled_back_inserters_bt { typedef boost::tuples::cons < geometry::range::back_insert_iterator < typename boost::tuples::element::type >, typename tupled_back_inserters_bt::type > type; static type apply(Tuple & tup) { return type(geometry::range::back_inserter(boost::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> : tupled_back_inserters_bt> {}; 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 : std::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 struct output_geometry_concept_check > : output_geometry_concept_check_t > {}; template struct output_geometry_concept_check > : output_geometry_concept_check_t > {}; template struct output_geometry_concept_check > : output_geometry_concept_check_t > {}; struct tupled_output_tag {}; template struct setop_insert_output_tag : std::conditional < 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_GEOMETRY_STATIC_ASSERT( IsFound, "PointLike Geometry expected in tupled output.", Geometry1, Geometry2, TupledOut); }; template struct expect_output_assert_base { BOOST_GEOMETRY_STATIC_ASSERT( IsFound, "Linear Geometry expected in tupled output.", Geometry1, Geometry2, TupledOut); }; template struct expect_output_assert_base { BOOST_GEOMETRY_STATIC_ASSERT( IsFound, "Areal Geometry expected in tupled output.", Geometry1, Geometry2, TupledOut); }; 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 ...Tags > 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 = util::is_multi::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) { for (auto 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