• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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