1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
5
6 // This file was modified by Oracle on 2013-2020.
7 // Modifications copyright (c) 2013-2020 Oracle and/or its affiliates.
8
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
14
15 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
17
18 #include <algorithm>
19 #include <cstddef>
20 #include <cstring>
21
22 #include <boost/mpl/assert.hpp>
23 #include <boost/mpl/at.hpp>
24 #include <boost/mpl/begin.hpp>
25 #include <boost/mpl/deref.hpp>
26 #include <boost/mpl/end.hpp>
27 #include <boost/mpl/is_sequence.hpp>
28 #include <boost/mpl/next.hpp>
29 #include <boost/mpl/size.hpp>
30 #include <boost/static_assert.hpp>
31 #include <boost/throw_exception.hpp>
32 #include <boost/tuple/tuple.hpp>
33 #include <boost/type_traits/integral_constant.hpp>
34
35 #include <boost/geometry/core/assert.hpp>
36 #include <boost/geometry/core/coordinate_dimension.hpp>
37 #include <boost/geometry/core/exception.hpp>
38 #include <boost/geometry/util/condition.hpp>
39
40 namespace boost { namespace geometry {
41
42 #ifndef DOXYGEN_NO_DETAIL
43 namespace detail { namespace relate {
44
45 enum field { interior = 0, boundary = 1, exterior = 2 };
46
47 // TODO: IF THE RESULT IS UPDATED WITH THE MAX POSSIBLE VALUE FOR SOME PAIR OF GEOEMTRIES
48 // THE VALUE ALREADY STORED MUSN'T BE CHECKED
49 // update() calls chould be replaced with set() in those cases
50 // but for safety reasons (STATIC_ASSERT) we should check if parameter D is valid and set() doesn't do that
51 // so some additional function could be added, e.g. set_dim()
52
53 // --------------- MATRIX ----------------
54
55 // matrix
56
57 template <std::size_t Height, std::size_t Width = Height>
58 class matrix
59 {
60 public:
61 typedef char value_type;
62 typedef std::size_t size_type;
63 typedef const char * const_iterator;
64 typedef const_iterator iterator;
65
66 static const std::size_t static_width = Width;
67 static const std::size_t static_height = Height;
68 static const std::size_t static_size = Width * Height;
69
matrix()70 inline matrix()
71 {
72 ::memset(m_array, 'F', static_size);
73 }
74
75 template <field F1, field F2>
get() const76 inline char get() const
77 {
78 BOOST_STATIC_ASSERT(F1 < Height && F2 < Width);
79 static const std::size_t index = F1 * Width + F2;
80 BOOST_STATIC_ASSERT(index < static_size);
81 return m_array[index];
82 }
83
84 template <field F1, field F2, char V>
set()85 inline void set()
86 {
87 BOOST_STATIC_ASSERT(F1 < Height && F2 < Width);
88 static const std::size_t index = F1 * Width + F2;
89 BOOST_STATIC_ASSERT(index < static_size);
90 m_array[index] = V;
91 }
92
operator [](std::size_t index) const93 inline char operator[](std::size_t index) const
94 {
95 BOOST_GEOMETRY_ASSERT(index < static_size);
96 return m_array[index];
97 }
98
begin() const99 inline const_iterator begin() const
100 {
101 return m_array;
102 }
103
end() const104 inline const_iterator end() const
105 {
106 return m_array + static_size;
107 }
108
size()109 inline static std::size_t size()
110 {
111 return static_size;
112 }
113
data() const114 inline const char * data() const
115 {
116 return m_array;
117 }
118
str() const119 inline std::string str() const
120 {
121 return std::string(m_array, static_size);
122 }
123
124 private:
125 char m_array[static_size];
126 };
127
128 // matrix_handler
129
130 template <typename Matrix>
131 class matrix_handler
132 {
133 public:
134 typedef Matrix result_type;
135
136 static const bool interrupt = false;
137
matrix_handler()138 matrix_handler()
139 {}
140
result() const141 result_type const& result() const
142 {
143 return m_matrix;
144 }
145
matrix() const146 result_type const& matrix() const
147 {
148 return m_matrix;
149 }
150
matrix()151 result_type & matrix()
152 {
153 return m_matrix;
154 }
155
156 template <field F1, field F2, char D>
may_update() const157 inline bool may_update() const
158 {
159 BOOST_STATIC_ASSERT('0' <= D && D <= '9');
160
161 char const c = m_matrix.template get<F1, F2>();
162 return D > c || c > '9';
163 }
164
165 template <field F1, field F2, char V>
set()166 inline void set()
167 {
168 static const bool in_bounds = F1 < Matrix::static_height
169 && F2 < Matrix::static_width;
170 typedef boost::integral_constant<bool, in_bounds> in_bounds_t;
171 set_dispatch<F1, F2, V>(in_bounds_t());
172 }
173
174 template <field F1, field F2, char D>
update()175 inline void update()
176 {
177 static const bool in_bounds = F1 < Matrix::static_height
178 && F2 < Matrix::static_width;
179 typedef boost::integral_constant<bool, in_bounds> in_bounds_t;
180 update_dispatch<F1, F2, D>(in_bounds_t());
181 }
182
183 private:
184 template <field F1, field F2, char V>
set_dispatch(integral_constant<bool,true>)185 inline void set_dispatch(integral_constant<bool, true>)
186 {
187 static const std::size_t index = F1 * Matrix::static_width + F2;
188 BOOST_STATIC_ASSERT(index < Matrix::static_size);
189 BOOST_STATIC_ASSERT(('0' <= V && V <= '9') || V == 'T' || V == 'F');
190 m_matrix.template set<F1, F2, V>();
191 }
192 template <field F1, field F2, char V>
set_dispatch(integral_constant<bool,false>)193 inline void set_dispatch(integral_constant<bool, false>)
194 {}
195
196 template <field F1, field F2, char D>
update_dispatch(integral_constant<bool,true>)197 inline void update_dispatch(integral_constant<bool, true>)
198 {
199 static const std::size_t index = F1 * Matrix::static_width + F2;
200 BOOST_STATIC_ASSERT(index < Matrix::static_size);
201 BOOST_STATIC_ASSERT('0' <= D && D <= '9');
202 char const c = m_matrix.template get<F1, F2>();
203 if ( D > c || c > '9')
204 m_matrix.template set<F1, F2, D>();
205 }
206 template <field F1, field F2, char D>
update_dispatch(integral_constant<bool,false>)207 inline void update_dispatch(integral_constant<bool, false>)
208 {}
209
210 Matrix m_matrix;
211 };
212
213 // --------------- RUN-TIME MASK ----------------
214
215 // run-time mask
216
217 template <std::size_t Height, std::size_t Width = Height>
218 class mask
219 {
220 public:
221 static const std::size_t static_width = Width;
222 static const std::size_t static_height = Height;
223 static const std::size_t static_size = Width * Height;
224
mask(const char * s)225 inline mask(const char * s)
226 {
227 char * it = m_array;
228 char * const last = m_array + static_size;
229 for ( ; it != last && *s != '\0' ; ++it, ++s )
230 {
231 char c = *s;
232 check_char(c);
233 *it = c;
234 }
235 if ( it != last )
236 {
237 ::memset(it, '*', last - it);
238 }
239 }
240
mask(const char * s,std::size_t count)241 inline mask(const char * s, std::size_t count)
242 {
243 if ( count > static_size )
244 {
245 count = static_size;
246 }
247 if ( count > 0 )
248 {
249 std::for_each(s, s + count, check_char);
250 ::memcpy(m_array, s, count);
251 }
252 if ( count < static_size )
253 {
254 ::memset(m_array + count, '*', static_size - count);
255 }
256 }
257
258 template <field F1, field F2>
get() const259 inline char get() const
260 {
261 BOOST_STATIC_ASSERT(F1 < Height && F2 < Width);
262 static const std::size_t index = F1 * Width + F2;
263 BOOST_STATIC_ASSERT(index < static_size);
264 return m_array[index];
265 }
266
267 private:
check_char(char c)268 static inline void check_char(char c)
269 {
270 bool const is_valid = c == '*' || c == 'T' || c == 'F'
271 || ( c >= '0' && c <= '9' );
272 if ( !is_valid )
273 {
274 BOOST_THROW_EXCEPTION(geometry::invalid_input_exception());
275 }
276 }
277
278 char m_array[static_size];
279 };
280
281 // interrupt()
282
283 template <typename Mask, bool InterruptEnabled>
284 struct interrupt_dispatch
285 {
286 template <field F1, field F2, char V>
applyboost::geometry::detail::relate::interrupt_dispatch287 static inline bool apply(Mask const&)
288 {
289 return false;
290 }
291 };
292
293 template <typename Mask>
294 struct interrupt_dispatch<Mask, true>
295 {
296 template <field F1, field F2, char V>
applyboost::geometry::detail::relate::interrupt_dispatch297 static inline bool apply(Mask const& mask)
298 {
299 char m = mask.template get<F1, F2>();
300 return check_element<V>(m);
301 }
302
303 template <char V>
check_elementboost::geometry::detail::relate::interrupt_dispatch304 static inline bool check_element(char m)
305 {
306 if ( BOOST_GEOMETRY_CONDITION(V >= '0' && V <= '9') )
307 {
308 return m == 'F' || ( m < V && m >= '0' && m <= '9' );
309 }
310 else if ( BOOST_GEOMETRY_CONDITION(V == 'T') )
311 {
312 return m == 'F';
313 }
314 return false;
315 }
316 };
317
318 template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
319 struct interrupt_dispatch_tuple
320 {
321 template <field F1, field F2, char V>
applyboost::geometry::detail::relate::interrupt_dispatch_tuple322 static inline bool apply(Masks const& masks)
323 {
324 typedef typename boost::tuples::element<I, Masks>::type mask_type;
325 mask_type const& mask = boost::get<I>(masks);
326 return interrupt_dispatch<mask_type, true>::template apply<F1, F2, V>(mask)
327 && interrupt_dispatch_tuple<Masks, I+1>::template apply<F1, F2, V>(masks);
328 }
329 };
330
331 template <typename Masks, int N>
332 struct interrupt_dispatch_tuple<Masks, N, N>
333 {
334 template <field F1, field F2, char V>
applyboost::geometry::detail::relate::interrupt_dispatch_tuple335 static inline bool apply(Masks const& )
336 {
337 return true;
338 }
339 };
340
341 //template <typename T0, typename T1, typename T2, typename T3, typename T4,
342 // typename T5, typename T6, typename T7, typename T8, typename T9>
343 //struct interrupt_dispatch<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>, true>
344 //{
345 // typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
346
347 // template <field F1, field F2, char V>
348 // static inline bool apply(mask_type const& mask)
349 // {
350 // return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask);
351 // }
352 //};
353
354 template <typename Head, typename Tail>
355 struct interrupt_dispatch<boost::tuples::cons<Head, Tail>, true>
356 {
357 typedef boost::tuples::cons<Head, Tail> mask_type;
358
359 template <field F1, field F2, char V>
applyboost::geometry::detail::relate::interrupt_dispatch360 static inline bool apply(mask_type const& mask)
361 {
362 return interrupt_dispatch_tuple<mask_type>::template apply<F1, F2, V>(mask);
363 }
364 };
365
366 template <field F1, field F2, char V, bool InterruptEnabled, typename Mask>
interrupt(Mask const & mask)367 inline bool interrupt(Mask const& mask)
368 {
369 return interrupt_dispatch<Mask, InterruptEnabled>
370 ::template apply<F1, F2, V>(mask);
371 }
372
373 // may_update()
374
375 template <typename Mask>
376 struct may_update_dispatch
377 {
378 template <field F1, field F2, char D, typename Matrix>
applyboost::geometry::detail::relate::may_update_dispatch379 static inline bool apply(Mask const& mask, Matrix const& matrix)
380 {
381 BOOST_STATIC_ASSERT('0' <= D && D <= '9');
382
383 char const m = mask.template get<F1, F2>();
384
385 if ( m == 'F' )
386 {
387 return true;
388 }
389 else if ( m == 'T' )
390 {
391 char const c = matrix.template get<F1, F2>();
392 return c == 'F'; // if it's T or between 0 and 9, the result will be the same
393 }
394 else if ( m >= '0' && m <= '9' )
395 {
396 char const c = matrix.template get<F1, F2>();
397 return D > c || c > '9';
398 }
399
400 return false;
401 }
402 };
403
404 template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
405 struct may_update_dispatch_tuple
406 {
407 template <field F1, field F2, char D, typename Matrix>
applyboost::geometry::detail::relate::may_update_dispatch_tuple408 static inline bool apply(Masks const& masks, Matrix const& matrix)
409 {
410 typedef typename boost::tuples::element<I, Masks>::type mask_type;
411 mask_type const& mask = boost::get<I>(masks);
412 return may_update_dispatch<mask_type>::template apply<F1, F2, D>(mask, matrix)
413 || may_update_dispatch_tuple<Masks, I+1>::template apply<F1, F2, D>(masks, matrix);
414 }
415 };
416
417 template <typename Masks, int N>
418 struct may_update_dispatch_tuple<Masks, N, N>
419 {
420 template <field F1, field F2, char D, typename Matrix>
applyboost::geometry::detail::relate::may_update_dispatch_tuple421 static inline bool apply(Masks const& , Matrix const& )
422 {
423 return false;
424 }
425 };
426
427 //template <typename T0, typename T1, typename T2, typename T3, typename T4,
428 // typename T5, typename T6, typename T7, typename T8, typename T9>
429 //struct may_update_dispatch< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
430 //{
431 // typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
432
433 // template <field F1, field F2, char D, typename Matrix>
434 // static inline bool apply(mask_type const& mask, Matrix const& matrix)
435 // {
436 // return may_update_dispatch_tuple<mask_type>::template apply<F1, F2, D>(mask, matrix);
437 // }
438 //};
439
440 template <typename Head, typename Tail>
441 struct may_update_dispatch< boost::tuples::cons<Head, Tail> >
442 {
443 typedef boost::tuples::cons<Head, Tail> mask_type;
444
445 template <field F1, field F2, char D, typename Matrix>
applyboost::geometry::detail::relate::may_update_dispatch446 static inline bool apply(mask_type const& mask, Matrix const& matrix)
447 {
448 return may_update_dispatch_tuple<mask_type>::template apply<F1, F2, D>(mask, matrix);
449 }
450 };
451
452 template <field F1, field F2, char D, typename Mask, typename Matrix>
may_update(Mask const & mask,Matrix const & matrix)453 inline bool may_update(Mask const& mask, Matrix const& matrix)
454 {
455 return may_update_dispatch<Mask>
456 ::template apply<F1, F2, D>(mask, matrix);
457 }
458
459 // check_matrix()
460
461 template <typename Mask>
462 struct check_dispatch
463 {
464 template <typename Matrix>
applyboost::geometry::detail::relate::check_dispatch465 static inline bool apply(Mask const& mask, Matrix const& matrix)
466 {
467 return per_one<interior, interior>(mask, matrix)
468 && per_one<interior, boundary>(mask, matrix)
469 && per_one<interior, exterior>(mask, matrix)
470 && per_one<boundary, interior>(mask, matrix)
471 && per_one<boundary, boundary>(mask, matrix)
472 && per_one<boundary, exterior>(mask, matrix)
473 && per_one<exterior, interior>(mask, matrix)
474 && per_one<exterior, boundary>(mask, matrix)
475 && per_one<exterior, exterior>(mask, matrix);
476 }
477
478 template <field F1, field F2, typename Matrix>
per_oneboost::geometry::detail::relate::check_dispatch479 static inline bool per_one(Mask const& mask, Matrix const& matrix)
480 {
481 const char mask_el = mask.template get<F1, F2>();
482 const char el = matrix.template get<F1, F2>();
483
484 if ( mask_el == 'F' )
485 {
486 return el == 'F';
487 }
488 else if ( mask_el == 'T' )
489 {
490 return el == 'T' || ( el >= '0' && el <= '9' );
491 }
492 else if ( mask_el >= '0' && mask_el <= '9' )
493 {
494 return el == mask_el;
495 }
496
497 return true;
498 }
499 };
500
501 template <typename Masks, int I = 0, int N = boost::tuples::length<Masks>::value>
502 struct check_dispatch_tuple
503 {
504 template <typename Matrix>
applyboost::geometry::detail::relate::check_dispatch_tuple505 static inline bool apply(Masks const& masks, Matrix const& matrix)
506 {
507 typedef typename boost::tuples::element<I, Masks>::type mask_type;
508 mask_type const& mask = boost::get<I>(masks);
509 return check_dispatch<mask_type>::apply(mask, matrix)
510 || check_dispatch_tuple<Masks, I+1>::apply(masks, matrix);
511 }
512 };
513
514 template <typename Masks, int N>
515 struct check_dispatch_tuple<Masks, N, N>
516 {
517 template <typename Matrix>
applyboost::geometry::detail::relate::check_dispatch_tuple518 static inline bool apply(Masks const&, Matrix const&)
519 {
520 return false;
521 }
522 };
523
524 //template <typename T0, typename T1, typename T2, typename T3, typename T4,
525 // typename T5, typename T6, typename T7, typename T8, typename T9>
526 //struct check_dispatch< boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
527 //{
528 // typedef boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> mask_type;
529
530 // template <typename Matrix>
531 // static inline bool apply(mask_type const& mask, Matrix const& matrix)
532 // {
533 // return check_dispatch_tuple<mask_type>::apply(mask, matrix);
534 // }
535 //};
536
537 template <typename Head, typename Tail>
538 struct check_dispatch< boost::tuples::cons<Head, Tail> >
539 {
540 typedef boost::tuples::cons<Head, Tail> mask_type;
541
542 template <typename Matrix>
applyboost::geometry::detail::relate::check_dispatch543 static inline bool apply(mask_type const& mask, Matrix const& matrix)
544 {
545 return check_dispatch_tuple<mask_type>::apply(mask, matrix);
546 }
547 };
548
549 template <typename Mask, typename Matrix>
check_matrix(Mask const & mask,Matrix const & matrix)550 inline bool check_matrix(Mask const& mask, Matrix const& matrix)
551 {
552 return check_dispatch<Mask>::apply(mask, matrix);
553 }
554
555 // matrix_width
556
557 template <typename MatrixOrMask>
558 struct matrix_width
559 {
560 static const std::size_t value = MatrixOrMask::static_width;
561 };
562
563 template <typename Tuple,
564 int I = 0,
565 int N = boost::tuples::length<Tuple>::value>
566 struct matrix_width_tuple
567 {
568 static const std::size_t
569 current = matrix_width<typename boost::tuples::element<I, Tuple>::type>::value;
570 static const std::size_t
571 next = matrix_width_tuple<Tuple, I+1>::value;
572
573 static const std::size_t
574 value = current > next ? current : next;
575 };
576
577 template <typename Tuple, int N>
578 struct matrix_width_tuple<Tuple, N, N>
579 {
580 static const std::size_t value = 0;
581 };
582
583 template <typename Head, typename Tail>
584 struct matrix_width< boost::tuples::cons<Head, Tail> >
585 {
586 static const std::size_t
587 value = matrix_width_tuple< boost::tuples::cons<Head, Tail> >::value;
588 };
589
590 // mask_handler
591
592 template <typename Mask, bool Interrupt>
593 class mask_handler
594 : private matrix_handler
595 <
596 relate::matrix<matrix_width<Mask>::value>
597 >
598 {
599 typedef matrix_handler
600 <
601 relate::matrix<matrix_width<Mask>::value>
602 > base_t;
603
604 public:
605 typedef bool result_type;
606
607 bool interrupt;
608
mask_handler(Mask const & m)609 inline explicit mask_handler(Mask const& m)
610 : interrupt(false)
611 , m_mask(m)
612 {}
613
result() const614 result_type result() const
615 {
616 return !interrupt
617 && check_matrix(m_mask, base_t::matrix());
618 }
619
620 template <field F1, field F2, char D>
may_update() const621 inline bool may_update() const
622 {
623 return detail::relate::may_update<F1, F2, D>(
624 m_mask, base_t::matrix()
625 );
626 }
627
628 template <field F1, field F2, char V>
set()629 inline void set()
630 {
631 if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) )
632 {
633 interrupt = true;
634 }
635 else
636 {
637 base_t::template set<F1, F2, V>();
638 }
639 }
640
641 template <field F1, field F2, char V>
update()642 inline void update()
643 {
644 if ( relate::interrupt<F1, F2, V, Interrupt>(m_mask) )
645 {
646 interrupt = true;
647 }
648 else
649 {
650 base_t::template update<F1, F2, V>();
651 }
652 }
653
654 private:
655 Mask const& m_mask;
656 };
657
658 // --------------- FALSE MASK ----------------
659
660 struct false_mask {};
661
662 // --------------- COMPILE-TIME MASK ----------------
663
664 // static_check_characters
665 template
666 <
667 typename Seq,
668 typename First = typename boost::mpl::begin<Seq>::type,
669 typename Last = typename boost::mpl::end<Seq>::type
670 >
671 struct static_check_characters
672 : static_check_characters
673 <
674 Seq,
675 typename boost::mpl::next<First>::type
676 >
677 {
678 typedef typename boost::mpl::deref<First>::type type;
679 static const char value = type::value;
680 static const bool is_valid = (value >= '0' && value <= '9')
681 || value == 'T' || value == 'F' || value == '*';
682 BOOST_MPL_ASSERT_MSG((is_valid),
683 INVALID_STATIC_MASK_CHARACTER,
684 (type));
685 };
686
687 template <typename Seq, typename Last>
688 struct static_check_characters<Seq, Last, Last>
689 {};
690
691 // static_mask
692
693 template
694 <
695 typename Seq,
696 std::size_t Height,
697 std::size_t Width = Height
698 >
699 struct static_mask
700 {
701 static const std::size_t static_width = Width;
702 static const std::size_t static_height = Height;
703 static const std::size_t static_size = Width * Height;
704
705 BOOST_STATIC_ASSERT(
706 std::size_t(boost::mpl::size<Seq>::type::value) == static_size);
707
708 template <detail::relate::field F1, detail::relate::field F2>
709 struct static_get
710 {
711 BOOST_STATIC_ASSERT(std::size_t(F1) < static_height);
712 BOOST_STATIC_ASSERT(std::size_t(F2) < static_width);
713
714 static const char value
715 = boost::mpl::at_c<Seq, F1 * static_width + F2>::type::value;
716 };
717
718 private:
719 // check static_mask characters
720 enum { mask_check = sizeof(static_check_characters<Seq>) };
721 };
722
723 // static_should_handle_element
724
725 template <typename StaticMask, field F1, field F2, bool IsSequence>
726 struct static_should_handle_element_dispatch
727 {
728 static const char mask_el = StaticMask::template static_get<F1, F2>::value;
729 static const bool value = mask_el == 'F'
730 || mask_el == 'T'
731 || ( mask_el >= '0' && mask_el <= '9' );
732 };
733
734 template <typename First, typename Last, field F1, field F2>
735 struct static_should_handle_element_sequence
736 {
737 typedef typename boost::mpl::deref<First>::type StaticMask;
738
739 static const bool value
740 = static_should_handle_element_dispatch
741 <
742 StaticMask,
743 F1, F2,
744 boost::mpl::is_sequence<StaticMask>::value
745 >::value
746 || static_should_handle_element_sequence
747 <
748 typename boost::mpl::next<First>::type,
749 Last,
750 F1, F2
751 >::value;
752 };
753
754 template <typename Last, field F1, field F2>
755 struct static_should_handle_element_sequence<Last, Last, F1, F2>
756 {
757 static const bool value = false;
758 };
759
760 template <typename StaticMask, field F1, field F2>
761 struct static_should_handle_element_dispatch<StaticMask, F1, F2, true>
762 {
763 static const bool value
764 = static_should_handle_element_sequence
765 <
766 typename boost::mpl::begin<StaticMask>::type,
767 typename boost::mpl::end<StaticMask>::type,
768 F1, F2
769 >::value;
770 };
771
772 template <typename StaticMask, field F1, field F2>
773 struct static_should_handle_element
774 {
775 static const bool value
776 = static_should_handle_element_dispatch
777 <
778 StaticMask,
779 F1, F2,
780 boost::mpl::is_sequence<StaticMask>::value
781 >::value;
782 };
783
784 // static_interrupt
785
786 template <typename StaticMask, char V, field F1, field F2, bool InterruptEnabled, bool IsSequence>
787 struct static_interrupt_dispatch
788 {
789 static const bool value = false;
790 };
791
792 template <typename StaticMask, char V, field F1, field F2, bool IsSequence>
793 struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, IsSequence>
794 {
795 static const char mask_el = StaticMask::template static_get<F1, F2>::value;
796
797 static const bool value
798 = ( V >= '0' && V <= '9' ) ?
799 ( mask_el == 'F' || ( mask_el < V && mask_el >= '0' && mask_el <= '9' ) ) :
800 ( ( V == 'T' ) ? mask_el == 'F' : false );
801 };
802
803 template <typename First, typename Last, char V, field F1, field F2>
804 struct static_interrupt_sequence
805 {
806 typedef typename boost::mpl::deref<First>::type StaticMask;
807
808 static const bool value
809 = static_interrupt_dispatch
810 <
811 StaticMask,
812 V, F1, F2,
813 true,
814 boost::mpl::is_sequence<StaticMask>::value
815 >::value
816 && static_interrupt_sequence
817 <
818 typename boost::mpl::next<First>::type,
819 Last,
820 V, F1, F2
821 >::value;
822 };
823
824 template <typename Last, char V, field F1, field F2>
825 struct static_interrupt_sequence<Last, Last, V, F1, F2>
826 {
827 static const bool value = true;
828 };
829
830 template <typename StaticMask, char V, field F1, field F2>
831 struct static_interrupt_dispatch<StaticMask, V, F1, F2, true, true>
832 {
833 static const bool value
834 = static_interrupt_sequence
835 <
836 typename boost::mpl::begin<StaticMask>::type,
837 typename boost::mpl::end<StaticMask>::type,
838 V, F1, F2
839 >::value;
840 };
841
842 template <typename StaticMask, char V, field F1, field F2, bool EnableInterrupt>
843 struct static_interrupt
844 {
845 static const bool value
846 = static_interrupt_dispatch
847 <
848 StaticMask,
849 V, F1, F2,
850 EnableInterrupt,
851 boost::mpl::is_sequence<StaticMask>::value
852 >::value;
853 };
854
855 // static_may_update
856
857 template <typename StaticMask, char D, field F1, field F2, bool IsSequence>
858 struct static_may_update_dispatch
859 {
860 static const char mask_el = StaticMask::template static_get<F1, F2>::value;
861 static const int version
862 = mask_el == 'F' ? 0
863 : mask_el == 'T' ? 1
864 : mask_el >= '0' && mask_el <= '9' ? 2
865 : 3;
866
867 template <typename Matrix>
applyboost::geometry::detail::relate::static_may_update_dispatch868 static inline bool apply(Matrix const& matrix)
869 {
870 return apply_dispatch(matrix, integral_constant<int, version>());
871 }
872
873 // mask_el == 'F'
874 template <typename Matrix>
apply_dispatchboost::geometry::detail::relate::static_may_update_dispatch875 static inline bool apply_dispatch(Matrix const& , integral_constant<int, 0>)
876 {
877 return true;
878 }
879 // mask_el == 'T'
880 template <typename Matrix>
apply_dispatchboost::geometry::detail::relate::static_may_update_dispatch881 static inline bool apply_dispatch(Matrix const& matrix, integral_constant<int, 1>)
882 {
883 char const c = matrix.template get<F1, F2>();
884 return c == 'F'; // if it's T or between 0 and 9, the result will be the same
885 }
886 // mask_el >= '0' && mask_el <= '9'
887 template <typename Matrix>
apply_dispatchboost::geometry::detail::relate::static_may_update_dispatch888 static inline bool apply_dispatch(Matrix const& matrix, integral_constant<int, 2>)
889 {
890 char const c = matrix.template get<F1, F2>();
891 return D > c || c > '9';
892 }
893 // else
894 template <typename Matrix>
apply_dispatchboost::geometry::detail::relate::static_may_update_dispatch895 static inline bool apply_dispatch(Matrix const&, integral_constant<int, 3>)
896 {
897 return false;
898 }
899 };
900
901 template <typename First, typename Last, char D, field F1, field F2>
902 struct static_may_update_sequence
903 {
904 typedef typename boost::mpl::deref<First>::type StaticMask;
905
906 template <typename Matrix>
applyboost::geometry::detail::relate::static_may_update_sequence907 static inline bool apply(Matrix const& matrix)
908 {
909 return static_may_update_dispatch
910 <
911 StaticMask,
912 D, F1, F2,
913 boost::mpl::is_sequence<StaticMask>::value
914 >::apply(matrix)
915 || static_may_update_sequence
916 <
917 typename boost::mpl::next<First>::type,
918 Last,
919 D, F1, F2
920 >::apply(matrix);
921 }
922 };
923
924 template <typename Last, char D, field F1, field F2>
925 struct static_may_update_sequence<Last, Last, D, F1, F2>
926 {
927 template <typename Matrix>
applyboost::geometry::detail::relate::static_may_update_sequence928 static inline bool apply(Matrix const& /*matrix*/)
929 {
930 return false;
931 }
932 };
933
934 template <typename StaticMask, char D, field F1, field F2>
935 struct static_may_update_dispatch<StaticMask, D, F1, F2, true>
936 {
937 template <typename Matrix>
applyboost::geometry::detail::relate::static_may_update_dispatch938 static inline bool apply(Matrix const& matrix)
939 {
940 return static_may_update_sequence
941 <
942 typename boost::mpl::begin<StaticMask>::type,
943 typename boost::mpl::end<StaticMask>::type,
944 D, F1, F2
945 >::apply(matrix);
946 }
947 };
948
949 template <typename StaticMask, char D, field F1, field F2>
950 struct static_may_update
951 {
952 template <typename Matrix>
applyboost::geometry::detail::relate::static_may_update953 static inline bool apply(Matrix const& matrix)
954 {
955 return static_may_update_dispatch
956 <
957 StaticMask,
958 D, F1, F2,
959 boost::mpl::is_sequence<StaticMask>::value
960 >::apply(matrix);
961 }
962 };
963
964 // static_check_matrix
965
966 template <typename StaticMask, bool IsSequence>
967 struct static_check_dispatch
968 {
969 template <typename Matrix>
applyboost::geometry::detail::relate::static_check_dispatch970 static inline bool apply(Matrix const& matrix)
971 {
972 return per_one<interior, interior>::apply(matrix)
973 && per_one<interior, boundary>::apply(matrix)
974 && per_one<interior, exterior>::apply(matrix)
975 && per_one<boundary, interior>::apply(matrix)
976 && per_one<boundary, boundary>::apply(matrix)
977 && per_one<boundary, exterior>::apply(matrix)
978 && per_one<exterior, interior>::apply(matrix)
979 && per_one<exterior, boundary>::apply(matrix)
980 && per_one<exterior, exterior>::apply(matrix);
981 }
982
983 template <field F1, field F2>
984 struct per_one
985 {
986 static const char mask_el = StaticMask::template static_get<F1, F2>::value;
987 static const int version
988 = mask_el == 'F' ? 0
989 : mask_el == 'T' ? 1
990 : mask_el >= '0' && mask_el <= '9' ? 2
991 : 3;
992
993 template <typename Matrix>
applyboost::geometry::detail::relate::static_check_dispatch::per_one994 static inline bool apply(Matrix const& matrix)
995 {
996 const char el = matrix.template get<F1, F2>();
997 return apply_dispatch(el, integral_constant<int, version>());
998 }
999
1000 // mask_el == 'F'
apply_dispatchboost::geometry::detail::relate::static_check_dispatch::per_one1001 static inline bool apply_dispatch(char el, integral_constant<int, 0>)
1002 {
1003 return el == 'F';
1004 }
1005 // mask_el == 'T'
apply_dispatchboost::geometry::detail::relate::static_check_dispatch::per_one1006 static inline bool apply_dispatch(char el, integral_constant<int, 1>)
1007 {
1008 return el == 'T' || ( el >= '0' && el <= '9' );
1009 }
1010 // mask_el >= '0' && mask_el <= '9'
apply_dispatchboost::geometry::detail::relate::static_check_dispatch::per_one1011 static inline bool apply_dispatch(char el, integral_constant<int, 2>)
1012 {
1013 return el == mask_el;
1014 }
1015 // else
apply_dispatchboost::geometry::detail::relate::static_check_dispatch::per_one1016 static inline bool apply_dispatch(char /*el*/, integral_constant<int, 3>)
1017 {
1018 return true;
1019 }
1020 };
1021 };
1022
1023 template <typename First, typename Last>
1024 struct static_check_sequence
1025 {
1026 typedef typename boost::mpl::deref<First>::type StaticMask;
1027
1028 template <typename Matrix>
applyboost::geometry::detail::relate::static_check_sequence1029 static inline bool apply(Matrix const& matrix)
1030 {
1031 return static_check_dispatch
1032 <
1033 StaticMask,
1034 boost::mpl::is_sequence<StaticMask>::value
1035 >::apply(matrix)
1036 || static_check_sequence
1037 <
1038 typename boost::mpl::next<First>::type,
1039 Last
1040 >::apply(matrix);
1041 }
1042 };
1043
1044 template <typename Last>
1045 struct static_check_sequence<Last, Last>
1046 {
1047 template <typename Matrix>
applyboost::geometry::detail::relate::static_check_sequence1048 static inline bool apply(Matrix const& /*matrix*/)
1049 {
1050 return false;
1051 }
1052 };
1053
1054 template <typename StaticMask>
1055 struct static_check_dispatch<StaticMask, true>
1056 {
1057 template <typename Matrix>
applyboost::geometry::detail::relate::static_check_dispatch1058 static inline bool apply(Matrix const& matrix)
1059 {
1060 return static_check_sequence
1061 <
1062 typename boost::mpl::begin<StaticMask>::type,
1063 typename boost::mpl::end<StaticMask>::type
1064 >::apply(matrix);
1065 }
1066 };
1067
1068 template <typename StaticMask>
1069 struct static_check_matrix
1070 {
1071 template <typename Matrix>
applyboost::geometry::detail::relate::static_check_matrix1072 static inline bool apply(Matrix const& matrix)
1073 {
1074 return static_check_dispatch
1075 <
1076 StaticMask,
1077 boost::mpl::is_sequence<StaticMask>::value
1078 >::apply(matrix);
1079 }
1080 };
1081
1082 // static_mask_handler
1083
1084 template <typename StaticMask, bool Interrupt>
1085 class static_mask_handler
1086 : private matrix_handler< matrix<3> >
1087 {
1088 typedef matrix_handler< relate::matrix<3> > base_type;
1089
1090 public:
1091 typedef bool result_type;
1092
1093 bool interrupt;
1094
static_mask_handler()1095 inline static_mask_handler()
1096 : interrupt(false)
1097 {}
1098
static_mask_handler(StaticMask const &)1099 inline explicit static_mask_handler(StaticMask const& /*dummy*/)
1100 : interrupt(false)
1101 {}
1102
result() const1103 result_type result() const
1104 {
1105 return (!Interrupt || !interrupt)
1106 && static_check_matrix<StaticMask>::apply(base_type::matrix());
1107 }
1108
1109 template <field F1, field F2, char D>
may_update() const1110 inline bool may_update() const
1111 {
1112 return static_may_update<StaticMask, D, F1, F2>::
1113 apply(base_type::matrix());
1114 }
1115
1116 template <field F1, field F2>
expects()1117 static inline bool expects()
1118 {
1119 return static_should_handle_element<StaticMask, F1, F2>::value;
1120 }
1121
1122 template <field F1, field F2, char V>
set()1123 inline void set()
1124 {
1125 static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value;
1126 static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value;
1127 static const int version = interrupt_c ? 0
1128 : should_handle ? 1
1129 : 2;
1130
1131 set_dispatch<F1, F2, V>(integral_constant<int, version>());
1132 }
1133
1134 template <field F1, field F2, char V>
update()1135 inline void update()
1136 {
1137 static const bool interrupt_c = static_interrupt<StaticMask, V, F1, F2, Interrupt>::value;
1138 static const bool should_handle = static_should_handle_element<StaticMask, F1, F2>::value;
1139 static const int version = interrupt_c ? 0
1140 : should_handle ? 1
1141 : 2;
1142
1143 update_dispatch<F1, F2, V>(integral_constant<int, version>());
1144 }
1145
1146 private:
1147 // Interrupt && interrupt
1148 template <field F1, field F2, char V>
set_dispatch(integral_constant<int,0>)1149 inline void set_dispatch(integral_constant<int, 0>)
1150 {
1151 interrupt = true;
1152 }
1153 // else should_handle
1154 template <field F1, field F2, char V>
set_dispatch(integral_constant<int,1>)1155 inline void set_dispatch(integral_constant<int, 1>)
1156 {
1157 base_type::template set<F1, F2, V>();
1158 }
1159 // else
1160 template <field F1, field F2, char V>
set_dispatch(integral_constant<int,2>)1161 inline void set_dispatch(integral_constant<int, 2>)
1162 {}
1163
1164 // Interrupt && interrupt
1165 template <field F1, field F2, char V>
update_dispatch(integral_constant<int,0>)1166 inline void update_dispatch(integral_constant<int, 0>)
1167 {
1168 interrupt = true;
1169 }
1170 // else should_handle
1171 template <field F1, field F2, char V>
update_dispatch(integral_constant<int,1>)1172 inline void update_dispatch(integral_constant<int, 1>)
1173 {
1174 base_type::template update<F1, F2, V>();
1175 }
1176 // else
1177 template <field F1, field F2, char V>
update_dispatch(integral_constant<int,2>)1178 inline void update_dispatch(integral_constant<int, 2>)
1179 {}
1180 };
1181
1182 // --------------- UTIL FUNCTIONS ----------------
1183
1184 // set
1185
1186 template <field F1, field F2, char V, typename Result>
set(Result & res)1187 inline void set(Result & res)
1188 {
1189 res.template set<F1, F2, V>();
1190 }
1191
1192 template <field F1, field F2, char V, bool Transpose>
1193 struct set_dispatch
1194 {
1195 template <typename Result>
applyboost::geometry::detail::relate::set_dispatch1196 static inline void apply(Result & res)
1197 {
1198 res.template set<F1, F2, V>();
1199 }
1200 };
1201
1202 template <field F1, field F2, char V>
1203 struct set_dispatch<F1, F2, V, true>
1204 {
1205 template <typename Result>
applyboost::geometry::detail::relate::set_dispatch1206 static inline void apply(Result & res)
1207 {
1208 res.template set<F2, F1, V>();
1209 }
1210 };
1211
1212 template <field F1, field F2, char V, bool Transpose, typename Result>
set(Result & res)1213 inline void set(Result & res)
1214 {
1215 set_dispatch<F1, F2, V, Transpose>::apply(res);
1216 }
1217
1218 // update
1219
1220 template <field F1, field F2, char D, typename Result>
update(Result & res)1221 inline void update(Result & res)
1222 {
1223 res.template update<F1, F2, D>();
1224 }
1225
1226 template <field F1, field F2, char D, bool Transpose>
1227 struct update_result_dispatch
1228 {
1229 template <typename Result>
applyboost::geometry::detail::relate::update_result_dispatch1230 static inline void apply(Result & res)
1231 {
1232 update<F1, F2, D>(res);
1233 }
1234 };
1235
1236 template <field F1, field F2, char D>
1237 struct update_result_dispatch<F1, F2, D, true>
1238 {
1239 template <typename Result>
applyboost::geometry::detail::relate::update_result_dispatch1240 static inline void apply(Result & res)
1241 {
1242 update<F2, F1, D>(res);
1243 }
1244 };
1245
1246 template <field F1, field F2, char D, bool Transpose, typename Result>
update(Result & res)1247 inline void update(Result & res)
1248 {
1249 update_result_dispatch<F1, F2, D, Transpose>::apply(res);
1250 }
1251
1252 // may_update
1253
1254 template <field F1, field F2, char D, typename Result>
may_update(Result const & res)1255 inline bool may_update(Result const& res)
1256 {
1257 return res.template may_update<F1, F2, D>();
1258 }
1259
1260 template <field F1, field F2, char D, bool Transpose>
1261 struct may_update_result_dispatch
1262 {
1263 template <typename Result>
applyboost::geometry::detail::relate::may_update_result_dispatch1264 static inline bool apply(Result const& res)
1265 {
1266 return may_update<F1, F2, D>(res);
1267 }
1268 };
1269
1270 template <field F1, field F2, char D>
1271 struct may_update_result_dispatch<F1, F2, D, true>
1272 {
1273 template <typename Result>
applyboost::geometry::detail::relate::may_update_result_dispatch1274 static inline bool apply(Result const& res)
1275 {
1276 return may_update<F2, F1, D>(res);
1277 }
1278 };
1279
1280 template <field F1, field F2, char D, bool Transpose, typename Result>
may_update(Result const & res)1281 inline bool may_update(Result const& res)
1282 {
1283 return may_update_result_dispatch<F1, F2, D, Transpose>::apply(res);
1284 }
1285
1286 // result_dimension
1287
1288 template <typename Geometry>
1289 struct result_dimension
1290 {
1291 BOOST_STATIC_ASSERT(geometry::dimension<Geometry>::value >= 0);
1292 static const char value
1293 = ( geometry::dimension<Geometry>::value <= 9 ) ?
1294 ( '0' + geometry::dimension<Geometry>::value ) :
1295 'T';
1296 };
1297
1298 }} // namespace detail::relate
1299 #endif // DOXYGEN_NO_DETAIL
1300
1301 }} // namespace boost::geometry
1302
1303 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP
1304