• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Boost.Geometry
2 
3 // Copyright (c) 2019-2020, Oracle and/or its affiliates.
4 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
5 
6 // Licensed under the Boost Software License version 1.0.
7 // http://www.boost.org/users/license.html
8 
9 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP
11 
12 #include <boost/geometry/algorithms/convert.hpp>
13 #include <boost/geometry/core/config.hpp>
14 #include <boost/geometry/core/tag.hpp>
15 #include <boost/geometry/core/tag_cast.hpp>
16 #include <boost/geometry/core/tags.hpp>
17 #include <boost/geometry/geometries/concepts/check.hpp>
18 #include <boost/geometry/util/range.hpp>
19 #include <boost/geometry/util/tuples.hpp>
20 
21 #include <boost/mpl/and.hpp>
22 #include <boost/mpl/if.hpp>
23 #include <boost/range/value_type.hpp>
24 #include <boost/type_traits/detail/yes_no_type.hpp>
25 #include <boost/type_traits/integral_constant.hpp>
26 #include <boost/type_traits/is_base_of.hpp>
27 #include <boost/type_traits/is_same.hpp>
28 #include <boost/type_traits/is_void.hpp>
29 
30 namespace boost { namespace geometry
31 {
32 
33 
34 #ifndef DOXYGEN_NO_DETAIL
35 namespace detail
36 {
37 
38 // true for any geometry
39 template <typename T>
40 struct is_geometry
41     : boost::integral_constant
42         <
43             bool,
44             (! boost::is_void<typename geometry::tag<T>::type>::value)
45         >
46 {};
47 
48 // true for multi-point, multi-linestring or multi-polygon
49 template <typename Geometry>
50 struct is_multi_geometry
51     : boost::is_base_of
52         <
53             geometry::multi_tag,
54             typename geometry::tag<Geometry>::type
55         >
56 {};
57 
58 // true for point, linestring or polygon
59 template <typename T>
60 struct is_multi_geometry_element
61     : boost::integral_constant
62         <
63             bool,
64             ((boost::is_same<typename geometry::tag<T>::type, point_tag>::value)
65             || (boost::is_same<typename geometry::tag<T>::type, linestring_tag>::value)
66             || (boost::is_same<typename geometry::tag<T>::type, polygon_tag>::value))
67         >
68 {};
69 
70 
71 template <typename T>
72 struct is_range_impl
73 {
74     typedef boost::type_traits::yes_type yes_type;
75     typedef boost::type_traits::no_type no_type;
76 
77     template <typename U>
78     static yes_type test(typename boost::range_iterator<U>::type*);
79 
80     template <typename U>
81     static no_type test(...);
82 
83     static const bool value = (sizeof(test<T>(0)) == sizeof(yes_type));
84 };
85 
86 // true if T is range (boost::range_iterator<T>::type is defined)
87 template <typename T>
88 struct is_range
89     : boost::integral_constant<bool, is_range_impl<T>::value>
90 {};
91 
92 
93 template <typename T, bool IsRange = is_range<T>::value>
94 struct is_tupled_output_element_base
95     : boost::integral_constant<bool, false>
96 {};
97 
98 template <typename T>
99 struct is_tupled_output_element_base<T, true>
100     : boost::integral_constant
101         <
102             bool,
103             (is_multi_geometry<T>::value
104                 ||
105                 ((! is_geometry<T>::value)
106                     &&
107                     is_multi_geometry_element
108                         <
109                             typename boost::range_value<T>::type
110                         >::value))
111         >
112 {};
113 
114 // true if T is a multi-geometry or is a range of points, linestrings or
115 // polygons
116 template <typename T>
117 struct is_tupled_output_element
118     : is_tupled_output_element_base<T>
119 {};
120 
121 
122 
123 // true if Output is not a geometry (so e.g. tuple was not adapted to any
124 // concept) and at least one of the tuple elements is a multi-geometry or
125 // a range of points, linestrings or polygons
126 template <typename Output>
127 struct is_tupled_output_check
128     : boost::mpl::and_
129         <
130             boost::is_same<typename geometry::tag<Output>::type, void>,
131             //geometry::tuples::exists_if<Output, is_multi_geometry>
132             geometry::tuples::exists_if<Output, is_tupled_output_element>
133         >
134 {};
135 
136 
137 // true if T is not a geometry (so e.g. tuple was not adapted to any
138 // concept) and at least one of the tuple elements is a point, linesting
139 // or polygon
140 template <typename T>
141 struct is_tupled_single_output_check
142     : boost::mpl::and_
143         <
144             boost::is_same<typename geometry::tag<T>::type, void>,
145             geometry::tuples::exists_if<T, is_multi_geometry_element>
146         >
147 {};
148 
149 
150 // true if Output is boost::tuple, boost::tuples::cons, std::pair or std::tuple
151 template <typename T>
152 struct is_tupled
153     : boost::integral_constant<bool, false>
154 {};
155 
156 template
157 <
158     class T0, class T1, class T2, class T3, class T4,
159     class T5, class T6, class T7, class T8, class T9
160 >
161 struct is_tupled<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
162     : boost::integral_constant<bool, true>
163 {};
164 
165 template <typename HT, typename TT>
166 struct is_tupled<boost::tuples::cons<HT, TT> >
167     : boost::integral_constant<bool, true>
168 {};
169 
170 template <typename F, typename S>
171 struct is_tupled<std::pair<F, S> >
172     : boost::integral_constant<bool, true>
173 {};
174 
175 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
176 
177 template <typename ...Ts>
178 struct is_tupled<std::tuple<Ts...> >
179     : boost::integral_constant<bool, true>
180 {};
181 
182 #endif // BOOST_GEOMETRY_CXX11_TUPLE
183 
184 
185 
186 // true if Output is boost::tuple, boost::tuples::cons, std::pair or std::tuple
187 // and is_tupled_output_check defiend above passes
188 template <typename Output, bool IsTupled = is_tupled<Output>::value>
189 struct is_tupled_output
190     : boost::integral_constant<bool, false>
191 {};
192 
193 template <typename Output>
194 struct is_tupled_output<Output, true>
195     : is_tupled_output_check<Output>
196 {};
197 
198 
199 // true if T is boost::tuple, boost::tuples::cons, std::pair or std::tuple
200 // and is_tupled_single_output_check defiend above passes
201 template <typename T, bool IsTupled = is_tupled<T>::value>
202 struct is_tupled_single_output
203     : boost::integral_constant<bool, false>
204 {};
205 
206 template <typename T>
207 struct is_tupled_single_output<T, true>
208     : is_tupled_single_output_check<T>
209 {};
210 
211 
212 template <typename Tag>
213 struct tupled_output_find_index_pred
214 {
215     template <typename T>
216     struct pred
217         : boost::is_same<typename geometry::tag<T>::type, Tag>
218     {};
219 };
220 
221 // Valid only if tupled_output_has<Output, Tag> is true
222 template <typename Output, typename Tag>
223 struct tupled_output_find_index
224     : geometry::tuples::find_index_if
225         <
226             Output,
227             tupled_output_find_index_pred<Tag>::template pred
228         >
229 {};
230 
231 
232 template
233 <
234     typename Output,
235     typename Tag,
236     bool IsTupledOutput = is_tupled_output<Output>::value
237 >
238 struct tupled_output_has
239     : boost::integral_constant<bool, false>
240 {};
241 
242 template <typename Output, typename Tag>
243 struct tupled_output_has<Output, Tag, true>
244     : boost::integral_constant
245         <
246             bool,
247             ((tupled_output_find_index<Output, Tag>::value)
248                 < (geometry::tuples::size<Output>::value))
249         >
250 {};
251 
252 
253 // Valid only if tupled_output_has<Output, Tag> is true
254 template <typename Tag, typename Output>
255 inline typename geometry::tuples::element
256     <
257         tupled_output_find_index<Output, Tag>::value,
258         Output
259     >::type &
tupled_output_get(Output & output)260 tupled_output_get(Output & output)
261 {
262     return geometry::tuples::get<tupled_output_find_index<Output, Tag>::value>(output);
263 }
264 
265 
266 // defines a tuple-type holding value-types of ranges being elements of
267 // Output pair/tuple
268 
269 template
270 <
271     typename Tuple,
272     size_t I = 0,
273     size_t N = geometry::tuples::size<Tuple>::value
274 >
275 struct tupled_range_values_bt
276 {
277     typedef boost::tuples::cons
278         <
279             typename boost::range_value
280                 <
281                     typename geometry::tuples::element<I, Tuple>::type
282                 >::type,
283             typename tupled_range_values_bt<Tuple, I+1, N>::type
284         > type;
285 };
286 
287 template <typename Tuple, size_t N>
288 struct tupled_range_values_bt<Tuple, N, N>
289 {
290     typedef boost::tuples::null_type type;
291 };
292 
293 template <typename Output>
294 struct tupled_range_values
295     : tupled_range_values_bt<Output>
296 {};
297 
298 template <typename F, typename S>
299 struct tupled_range_values<std::pair<F, S> >
300 {
301     typedef std::pair
302         <
303             typename boost::range_value<F>::type,
304             typename boost::range_value<S>::type
305         > type;
306 };
307 
308 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
309 
310 template <typename ...Ts>
311 struct tupled_range_values<std::tuple<Ts...> >
312 {
313     typedef std::tuple<typename boost::range_value<Ts>::type...> type;
314 };
315 
316 #endif // BOOST_GEOMETRY_CXX11_TUPLE
317 
318 
319 // util defining a type and creating a tuple holding back-insert-iterators to
320 // ranges being elements of Output pair/tuple
321 
322 template <typename Tuple,
323           size_t I = 0,
324           size_t N = geometry::tuples::size<Tuple>::value>
325 struct tupled_back_inserters_bt
326 {
327     typedef boost::tuples::cons
328         <
329             geometry::range::back_insert_iterator
330                 <
331                     typename geometry::tuples::element<I, Tuple>::type
332                 >,
333             typename tupled_back_inserters_bt<Tuple, I+1, N>::type
334         > type;
335 
applyboost::geometry::detail::tupled_back_inserters_bt336     static type apply(Tuple & tup)
337     {
338         return type(geometry::range::back_inserter(geometry::tuples::get<I>(tup)),
339                     tupled_back_inserters_bt<Tuple, I+1, N>::apply(tup));
340     }
341 };
342 
343 template <typename Tuple, size_t N>
344 struct tupled_back_inserters_bt<Tuple, N, N>
345 {
346     typedef boost::tuples::null_type type;
347 
applyboost::geometry::detail::tupled_back_inserters_bt348     static type apply(Tuple const&)
349     {
350         return type();
351     }
352 };
353 
354 template <typename Tuple>
355 struct tupled_back_inserters
356     : tupled_back_inserters_bt<Tuple>
357 {};
358 
359 template <typename F, typename S>
360 struct tupled_back_inserters<std::pair<F, S> >
361 {
362     typedef std::pair
363         <
364             geometry::range::back_insert_iterator<F>,
365             geometry::range::back_insert_iterator<S>
366         > type;
367 
applyboost::geometry::detail::tupled_back_inserters368     static type apply(std::pair<F, S> & p)
369     {
370         return type(geometry::range::back_inserter(p.first),
371                     geometry::range::back_inserter(p.second));
372     }
373 };
374 
375 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
376 
377 // NOTE: In C++14 std::integer_sequence and std::make_integer_sequence could be used
378 
379 template <typename Is, typename Tuple>
380 struct tupled_back_inserters_st;
381 
382 template <int ...Is, typename ...Ts>
383 struct tupled_back_inserters_st<geometry::tuples::int_sequence<Is...>, std::tuple<Ts...> >
384 {
385     typedef std::tuple<geometry::range::back_insert_iterator<Ts>...> type;
386 
applyboost::geometry::detail::tupled_back_inserters_st387     static type apply(std::tuple<Ts...> & tup)
388     {
389         return type(geometry::range::back_inserter(std::get<Is>(tup))...);
390     }
391 };
392 
393 template <typename ...Ts>
394 struct tupled_back_inserters<std::tuple<Ts...> >
395     : tupled_back_inserters_st
396         <
397             typename geometry::tuples::make_int_sequence<sizeof...(Ts)>::type,
398             std::tuple<Ts...>
399         >
400 {};
401 
402 #endif // BOOST_GEOMETRY_CXX11_TUPLE
403 
404 
405 template
406 <
407     typename GeometryOut,
408     bool IsTupled = is_tupled_output<GeometryOut>::value
409 >
410 struct output_geometry_value
411     : boost::range_value<GeometryOut>
412 {};
413 
414 template <typename GeometryOut>
415 struct output_geometry_value<GeometryOut, true>
416     : tupled_range_values<GeometryOut>
417 {};
418 
419 
420 template
421 <
422     typename GeometryOut,
423     bool IsTupled = is_tupled_output<GeometryOut>::value
424 >
425 struct output_geometry_back_inserter_
426 {
427     typedef geometry::range::back_insert_iterator<GeometryOut> type;
428 
applyboost::geometry::detail::output_geometry_back_inserter_429     static type apply(GeometryOut & out)
430     {
431         return geometry::range::back_inserter(out);
432     }
433 };
434 
435 template <typename GeometryOut>
436 struct output_geometry_back_inserter_<GeometryOut, true>
437     : tupled_back_inserters<GeometryOut>
438 {};
439 
440 template <typename GeometryOut>
441 inline typename output_geometry_back_inserter_<GeometryOut>::type
output_geometry_back_inserter(GeometryOut & out)442 output_geometry_back_inserter(GeometryOut & out)
443 {
444     return output_geometry_back_inserter_<GeometryOut>::apply(out);
445 }
446 
447 
448 // is_tag_same_as_pred
449 // Defines a predicate true if type's tag is the same as Tag
450 template <typename Tag>
451 struct is_tag_same_as_pred
452 {
453     template <typename T>
454     struct pred
455         : boost::is_same<typename geometry::tag<T>::type, Tag>
456     {};
457 };
458 
459 
460 // Allows to access a type/object in a pair/tuple corresponding to an index in
461 // GeometryOut pair/tuple of a geometry defined by Tag.
462 // If GeometryOut is a geometry then it's expected to be defined by DefaultTag.
463 template
464 <
465     typename GeometryOut,
466     typename Tag,
467     typename DefaultTag,
468     typename GeometryTag = typename geometry::tag<GeometryOut>::type
469 >
470 struct output_geometry_access
471 {};
472 
473 // assume GeometryTag is void because not adapted tuple holding geometries was passed
474 template <typename TupledOut, typename Tag, typename DefaultTag>
475 struct output_geometry_access<TupledOut, Tag, DefaultTag, void>
476 {
477     static const int index = geometry::tuples::find_index_if
478         <
479             TupledOut, is_tag_same_as_pred<Tag>::template pred
480         >::value;
481 
482     typedef typename geometry::tuples::element<index, TupledOut>::type type;
483 
484     template <typename Tuple>
485     static typename geometry::tuples::element<index, Tuple>::type&
getboost::geometry::detail::output_geometry_access486         get(Tuple & tup)
487     {
488         return geometry::tuples::get<index>(tup);
489     }
490 };
491 
492 template <typename GeometryOut, typename Tag, typename DefaultTag>
493 struct output_geometry_access<GeometryOut, Tag, DefaultTag, DefaultTag>
494 {
495     typedef GeometryOut type;
496 
497     template <typename T>
getboost::geometry::detail::output_geometry_access498     static T& get(T & v)
499     {
500         return v;
501     }
502 };
503 
504 
505 template <typename Geometry>
506 struct output_geometry_concept_check
507 {
applyboost::geometry::detail::output_geometry_concept_check508     static void apply()
509     {
510         concepts::check<Geometry>();
511     }
512 };
513 
514 template <typename First, typename Second>
515 struct output_geometry_concept_check<std::pair<First, Second> >
516 {
applyboost::geometry::detail::output_geometry_concept_check517     static void apply()
518     {
519         concepts::check<First>();
520         concepts::check<Second>();
521     }
522 };
523 
524 template <typename Tuple,
525           size_t I = 0,
526           size_t N = geometry::tuples::size<Tuple>::value>
527 struct output_geometry_concept_check_t
528 {
applyboost::geometry::detail::output_geometry_concept_check_t529     static void apply()
530     {
531         concepts::check<typename geometry::tuples::element<I, Tuple>::type>();
532         output_geometry_concept_check_t<Tuple, I + 1, N>::apply();
533     }
534 };
535 
536 template <typename Tuple, size_t N>
537 struct output_geometry_concept_check_t<Tuple, N, N>
538 {
applyboost::geometry::detail::output_geometry_concept_check_t539     static void apply()
540     {}
541 };
542 
543 template
544 <
545     class T0, class T1, class T2, class T3, class T4,
546     class T5, class T6, class T7, class T8, class T9
547 >
548 struct output_geometry_concept_check<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
549     : output_geometry_concept_check_t<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
550 {};
551 
552 template <typename HT, typename TT>
553 struct output_geometry_concept_check<boost::tuples::cons<HT, TT> >
554     : output_geometry_concept_check_t<boost::tuples::cons<HT, TT> >
555 {};
556 
557 #ifdef BOOST_GEOMETRY_CXX11_TUPLE
558 
559 template <typename ...Ts>
560 struct output_geometry_concept_check<std::tuple<Ts...> >
561     : output_geometry_concept_check_t<std::tuple<Ts...> >
562 {};
563 
564 #endif // BOOST_GEOMETRY_CXX11_TUPLE
565 
566 
567 struct tupled_output_tag {};
568 
569 
570 template <typename GeometryOut>
571 struct setop_insert_output_tag
572     : boost::mpl::if_c
573         <
574             geometry::detail::is_tupled_single_output<GeometryOut>::value,
575             tupled_output_tag,
576             typename geometry::tag<GeometryOut>::type
577         >
578 {};
579 
580 
581 template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound, typename Tag>
582 struct expect_output_assert_base;
583 
584 template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
585 struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, pointlike_tag>
586 {
587     BOOST_MPL_ASSERT_MSG
588         (
589             IsFound, POINTLIKE_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
590             (types<Geometry1, Geometry2, TupledOut>)
591         );
592 };
593 
594 template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
595 struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, linear_tag>
596 {
597     BOOST_MPL_ASSERT_MSG
598     (
599         IsFound, LINEAR_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
600         (types<Geometry1, Geometry2, TupledOut>)
601     );
602 };
603 
604 template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
605 struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, areal_tag>
606 {
607     BOOST_MPL_ASSERT_MSG
608     (
609         IsFound, AREAL_GEOMETRY_EXPECTED_IN_TUPLED_OUTPUT,
610         (types<Geometry1, Geometry2, TupledOut>)
611     );
612 };
613 
614 
615 template <typename Geometry1, typename Geometry2, typename TupledOut, typename Tag>
616 struct expect_output_assert
617     : expect_output_assert_base
618         <
619             Geometry1, Geometry2, TupledOut,
620             geometry::tuples::exists_if
621                 <
622                     TupledOut,
623                     is_tag_same_as_pred<Tag>::template pred
624                 >::value,
625             typename geometry::tag_cast
626                 <
627                     Tag, pointlike_tag, linear_tag, areal_tag
628                 >::type
629         >
630 {};
631 
632 template <typename Geometry1, typename Geometry2, typename TupledOut>
633 struct expect_output_assert<Geometry1, Geometry2, TupledOut, void>
634 {};
635 
636 template
637 <
638     typename Geometry1, typename Geometry2, typename TupledOut,
639     typename Tag1,
640     typename Tag2 = void,
641     typename Tag3 = void
642 >
643 struct expect_output
644     : expect_output_assert<Geometry1, Geometry2, TupledOut, Tag1>
645     , expect_output_assert<Geometry1, Geometry2, TupledOut, Tag2>
646     , expect_output_assert<Geometry1, Geometry2, TupledOut, Tag3>
647 {};
648 
649 template
650 <
651     typename Geometry1, typename Geometry2, typename TupledOut,
652     typename Tag1, typename Tag2
653 >
654 struct expect_output<Geometry1, Geometry2, TupledOut, Tag1, Tag2, void>
655     : expect_output_assert<Geometry1, Geometry2, TupledOut, Tag1>
656     , expect_output_assert<Geometry1, Geometry2, TupledOut, Tag2>
657 {};
658 
659 template
660 <
661     typename Geometry1, typename Geometry2, typename TupledOut,
662     typename Tag1
663 >
664 struct expect_output<Geometry1, Geometry2, TupledOut, Tag1, void, void>
665     : expect_output_assert<Geometry1, Geometry2, TupledOut, Tag1>
666 {};
667 
668 
669 template <typename CastedTag>
670 struct single_tag_from_base_tag;
671 
672 template <>
673 struct single_tag_from_base_tag<pointlike_tag>
674 {
675     typedef point_tag type;
676 };
677 
678 template <>
679 struct single_tag_from_base_tag<linear_tag>
680 {
681     typedef linestring_tag type;
682 };
683 
684 template <>
685 struct single_tag_from_base_tag<areal_tag>
686 {
687     typedef polygon_tag type;
688 };
689 
690 
691 template
692 <
693     typename Geometry,
694     typename SingleOut,
695     bool IsMulti = geometry::detail::is_multi_geometry<Geometry>::value
696 >
697 struct convert_to_output
698 {
699     template <typename OutputIterator>
applyboost::geometry::detail::convert_to_output700     static OutputIterator apply(Geometry const& geometry,
701                                 OutputIterator oit)
702     {
703         SingleOut single_out;
704         geometry::convert(geometry, single_out);
705         *oit++ = single_out;
706         return oit;
707     }
708 };
709 
710 template
711 <
712     typename Geometry,
713     typename SingleOut
714 >
715 struct convert_to_output<Geometry, SingleOut, true>
716 {
717     template <typename OutputIterator>
applyboost::geometry::detail::convert_to_output718     static OutputIterator apply(Geometry const& geometry,
719                                 OutputIterator oit)
720     {
721         typedef typename boost::range_iterator<Geometry const>::type iterator;
722         for (iterator it = boost::begin(geometry); it != boost::end(geometry); ++it)
723         {
724             SingleOut single_out;
725             geometry::convert(*it, single_out);
726             *oit++ = single_out;
727         }
728         return oit;
729     }
730 };
731 
732 
733 } // namespace detail
734 #endif // DOXYGEN_NO_DETAIL
735 
736 }} // namespace boost::geometry
737 
738 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP
739