tupled_output.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. // Boost.Geometry
  2. // Copyright (c) 2019-2020, Oracle and/or its affiliates.
  3. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
  4. // Licensed under the Boost Software License version 1.0.
  5. // http://www.boost.org/users/license.html
  6. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP
  7. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP
  8. #include <boost/geometry/core/config.hpp>
  9. #include <boost/geometry/core/tag.hpp>
  10. #include <boost/geometry/core/tags.hpp>
  11. #include <boost/geometry/util/range.hpp>
  12. #include <boost/geometry/util/tuples.hpp>
  13. #include <boost/mpl/and.hpp>
  14. #include <boost/range/value_type.hpp>
  15. #include <boost/type_traits/detail/yes_no_type.hpp>
  16. #include <boost/type_traits/integral_constant.hpp>
  17. #include <boost/type_traits/is_base_of.hpp>
  18. #include <boost/type_traits/is_same.hpp>
  19. #include <boost/type_traits/is_void.hpp>
  20. namespace boost { namespace geometry
  21. {
  22. #ifndef DOXYGEN_NO_DETAIL
  23. namespace detail
  24. {
  25. // true for any geometry
  26. template <typename T>
  27. struct is_geometry
  28. : boost::integral_constant
  29. <
  30. bool,
  31. (! boost::is_void<typename geometry::tag<T>::type>::value)
  32. >
  33. {};
  34. // true for multi-point, multi-linestring or multi-polygon
  35. template <typename Geometry>
  36. struct is_multi_geometry
  37. : boost::is_base_of
  38. <
  39. geometry::multi_tag,
  40. typename geometry::tag<Geometry>::type
  41. >
  42. {};
  43. // true for point, linestring or polygon
  44. template <typename T>
  45. struct is_multi_geometry_value
  46. : boost::integral_constant
  47. <
  48. bool,
  49. ((boost::is_same<typename geometry::tag<T>::type, point_tag>::value)
  50. || (boost::is_same<typename geometry::tag<T>::type, linestring_tag>::value)
  51. || (boost::is_same<typename geometry::tag<T>::type, polygon_tag>::value))
  52. >
  53. {};
  54. template <typename T>
  55. struct is_range_impl
  56. {
  57. typedef boost::type_traits::yes_type yes_type;
  58. typedef boost::type_traits::no_type no_type;
  59. template <typename U>
  60. static yes_type test(typename boost::range_iterator<U>::type*);
  61. template <typename U>
  62. static no_type test(...);
  63. static const bool value = (sizeof(test<T>(0)) == sizeof(yes_type));
  64. };
  65. // true if T is range (boost::range_iterator<T>::type is defined)
  66. template <typename T>
  67. struct is_range
  68. : boost::integral_constant<bool, is_range_impl<T>::value>
  69. {};
  70. // geometry tag of Rng value_type
  71. template <typename Rng>
  72. struct range_value_tag
  73. : geometry::tag<typename boost::range_value<Rng>::type>
  74. {};
  75. // true if geometry tag of Rng is the same as Tag
  76. template <typename Rng, typename Tag>
  77. struct is_range_value_tag_same_as
  78. : boost::is_same
  79. <
  80. typename range_value_tag<Rng>::type,
  81. Tag
  82. >
  83. {};
  84. template <typename T, bool IsRange = is_range<T>::value>
  85. struct is_tupled_output_element_base
  86. : boost::integral_constant<bool, false>
  87. {};
  88. template <typename T>
  89. struct is_tupled_output_element_base<T, true>
  90. : boost::integral_constant
  91. <
  92. bool,
  93. (is_multi_geometry<T>::value
  94. ||
  95. ((! is_geometry<T>::value)
  96. &&
  97. ((is_range_value_tag_same_as<T, point_tag>::value)
  98. || (is_range_value_tag_same_as<T, linestring_tag>::value)
  99. || (is_range_value_tag_same_as<T, polygon_tag>::value))))
  100. >
  101. {};
  102. // true if T is a multi-geometry or is a range of points, linestrings or
  103. // polygons
  104. template <typename T>
  105. struct is_tupled_output_element
  106. : is_tupled_output_element_base<T>
  107. {};
  108. // true if Output is not a geometry (so e.g. tuple was not adapted to any
  109. // concept) and at least one of the tuple elements is a multi-geometry or
  110. // a range of points linestrings or polygons
  111. template <typename Output>
  112. struct is_tupled_output_check
  113. : boost::mpl::and_
  114. <
  115. boost::is_same<typename geometry::tag<Output>::type, void>,
  116. //geometry::tuples::exists_if<Output, is_multi_geometry>
  117. geometry::tuples::exists_if<Output, is_tupled_output_element>
  118. >
  119. {};
  120. // true if T is a point, linestring or polygon
  121. template <typename T>
  122. struct is_tupled_range_values_element
  123. : boost::integral_constant
  124. <
  125. bool,
  126. ((boost::is_same<typename geometry::tag<T>::type, point_tag>::value)
  127. || (boost::is_same<typename geometry::tag<T>::type, linestring_tag>::value)
  128. || (boost::is_same<typename geometry::tag<T>::type, polygon_tag>::value))
  129. >
  130. {};
  131. // true if T is not a geometry (so e.g. tuple was not adapted to any
  132. // concept) and at least one of the tuple elements is a point, linesting
  133. // or polygon
  134. template <typename T>
  135. struct is_tupled_range_values_check
  136. : boost::mpl::and_
  137. <
  138. boost::is_same<typename geometry::tag<T>::type, void>,
  139. geometry::tuples::exists_if<T, is_tupled_range_values_element>
  140. >
  141. {};
  142. // true if Output is boost::tuple, boost::tuples::cons, std::pair or std::tuple
  143. template <typename T>
  144. struct is_tupled
  145. : boost::integral_constant<bool, false>
  146. {};
  147. template
  148. <
  149. class T0, class T1, class T2, class T3, class T4,
  150. class T5, class T6, class T7, class T8, class T9
  151. >
  152. struct is_tupled<boost::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> >
  153. : boost::integral_constant<bool, true>
  154. {};
  155. template <typename HT, typename TT>
  156. struct is_tupled<boost::tuples::cons<HT, TT> >
  157. : boost::integral_constant<bool, true>
  158. {};
  159. template <typename F, typename S>
  160. struct is_tupled<std::pair<F, S> >
  161. : boost::integral_constant<bool, true>
  162. {};
  163. #ifdef BOOST_GEOMETRY_CXX11_TUPLE
  164. template <typename ...Ts>
  165. struct is_tupled<std::tuple<Ts...> >
  166. : boost::integral_constant<bool, true>
  167. {};
  168. #endif // BOOST_GEOMETRY_CXX11_TUPLE
  169. // true if Output is boost::tuple, boost::tuples::cons, std::pair or std::tuple
  170. // and is_tupled_output_check defiend above passes
  171. template <typename Output, bool IsTupled = is_tupled<Output>::value>
  172. struct is_tupled_output
  173. : boost::integral_constant<bool, false>
  174. {};
  175. template <typename Output>
  176. struct is_tupled_output<Output, true>
  177. : is_tupled_output_check<Output>
  178. {};
  179. // true if T is boost::tuple, boost::tuples::cons, std::pair or std::tuple
  180. // and is_tupled_range_values_check defiend above passes
  181. template <typename T, bool IsTupled = is_tupled<T>::value>
  182. struct is_tupled_range_values
  183. : boost::integral_constant<bool, false>
  184. {};
  185. template <typename T>
  186. struct is_tupled_range_values<T, true>
  187. : is_tupled_range_values_check<T>
  188. {};
  189. template <typename Tag>
  190. struct tupled_output_find_index_pred
  191. {
  192. template <typename T>
  193. struct pred
  194. : boost::is_same<typename geometry::tag<T>::type, Tag>
  195. {};
  196. };
  197. // Valid only if tupled_output_has<Output, Tag> is true
  198. template <typename Output, typename Tag>
  199. struct tupled_output_find_index
  200. : geometry::tuples::find_index_if
  201. <
  202. Output,
  203. tupled_output_find_index_pred<Tag>::template pred
  204. >
  205. {};
  206. template
  207. <
  208. typename Output,
  209. typename Tag,
  210. bool IsTupledOutput = is_tupled_output<Output>::value
  211. >
  212. struct tupled_output_has
  213. : boost::integral_constant<bool, false>
  214. {};
  215. template <typename Output, typename Tag>
  216. struct tupled_output_has<Output, Tag, true>
  217. : boost::integral_constant
  218. <
  219. bool,
  220. ((tupled_output_find_index<Output, Tag>::value)
  221. < (geometry::tuples::size<Output>::value))
  222. >
  223. {};
  224. // Valid only if tupled_output_has<Output, Tag> is true
  225. template <typename Tag, typename Output>
  226. inline typename geometry::tuples::element
  227. <
  228. tupled_output_find_index<Output, Tag>::value,
  229. Output
  230. >::type &
  231. tupled_output_get(Output & output)
  232. {
  233. return geometry::tuples::get<tupled_output_find_index<Output, Tag>::value>(output);
  234. }
  235. // defines a tuple-type holding value-types of ranges being elements of
  236. // Output pair/tuple
  237. template
  238. <
  239. typename Tuple,
  240. size_t I = 0,
  241. size_t N = geometry::tuples::size<Tuple>::value
  242. >
  243. struct tupled_range_values_bt
  244. {
  245. typedef boost::tuples::cons
  246. <
  247. typename boost::range_value
  248. <
  249. typename geometry::tuples::element<I, Tuple>::type
  250. >::type,
  251. typename tupled_range_values_bt<Tuple, I+1, N>::type
  252. > type;
  253. };
  254. template <typename Tuple, size_t N>
  255. struct tupled_range_values_bt<Tuple, N, N>
  256. {
  257. typedef boost::tuples::null_type type;
  258. };
  259. template <typename Output>
  260. struct tupled_range_values
  261. : tupled_range_values_bt<Output>
  262. {};
  263. template <typename F, typename S>
  264. struct tupled_range_values<std::pair<F, S> >
  265. {
  266. typedef std::pair
  267. <
  268. typename boost::range_value<F>::type,
  269. typename boost::range_value<S>::type
  270. > type;
  271. };
  272. #ifdef BOOST_GEOMETRY_CXX11_TUPLE
  273. template <typename ...Ts>
  274. struct tupled_range_values<std::tuple<Ts...> >
  275. {
  276. typedef std::tuple<typename boost::range_value<Ts>::type...> type;
  277. };
  278. #endif // BOOST_GEOMETRY_CXX11_TUPLE
  279. // util defining a type and creating a tuple holding back-insert-iterators to
  280. // ranges being elements of Output pair/tuple
  281. template <typename Tuple,
  282. size_t I = 0,
  283. size_t N = geometry::tuples::size<Tuple>::value>
  284. struct tupled_back_inserters_bt
  285. {
  286. typedef boost::tuples::cons
  287. <
  288. geometry::range::back_insert_iterator
  289. <
  290. typename geometry::tuples::element<I, Tuple>::type
  291. >,
  292. typename tupled_back_inserters_bt<Tuple, I+1, N>::type
  293. > type;
  294. static type apply(Tuple & tup)
  295. {
  296. return type(geometry::range::back_inserter(geometry::tuples::get<I>(tup)),
  297. tupled_back_inserters_bt<Tuple, I+1, N>::apply(tup));
  298. }
  299. };
  300. template <typename Tuple, size_t N>
  301. struct tupled_back_inserters_bt<Tuple, N, N>
  302. {
  303. typedef boost::tuples::null_type type;
  304. static type apply(Tuple const&)
  305. {
  306. return type();
  307. }
  308. };
  309. template <typename Tuple>
  310. struct tupled_back_inserters
  311. : tupled_back_inserters_bt<Tuple>
  312. {};
  313. template <typename F, typename S>
  314. struct tupled_back_inserters<std::pair<F, S> >
  315. {
  316. typedef std::pair
  317. <
  318. geometry::range::back_insert_iterator<F>,
  319. geometry::range::back_insert_iterator<S>
  320. > type;
  321. static type apply(std::pair<F, S> & p)
  322. {
  323. return type(geometry::range::back_inserter(p.first),
  324. geometry::range::back_inserter(p.second));
  325. }
  326. };
  327. #ifdef BOOST_GEOMETRY_CXX11_TUPLE
  328. // NOTE: In C++14 std::integer_sequence and std::make_integer_sequence could be used
  329. template <typename Is, typename Tuple>
  330. struct tupled_back_inserters_st;
  331. template <int ...Is, typename ...Ts>
  332. struct tupled_back_inserters_st<geometry::tuples::int_sequence<Is...>, std::tuple<Ts...> >
  333. {
  334. typedef std::tuple<geometry::range::back_insert_iterator<Ts>...> type;
  335. static type apply(std::tuple<Ts...> & tup)
  336. {
  337. return type(geometry::range::back_inserter(std::get<Is>(tup))...);
  338. }
  339. };
  340. template <typename ...Ts>
  341. struct tupled_back_inserters<std::tuple<Ts...> >
  342. : tupled_back_inserters_st
  343. <
  344. typename geometry::tuples::make_int_sequence<sizeof...(Ts)>::type,
  345. std::tuple<Ts...>
  346. >
  347. {};
  348. #endif // BOOST_GEOMETRY_CXX11_TUPLE
  349. template
  350. <
  351. typename GeometryOut,
  352. bool IsTupled = is_tupled_output<GeometryOut>::value
  353. >
  354. struct output_geometry_value
  355. : boost::range_value<GeometryOut>
  356. {};
  357. template <typename GeometryOut>
  358. struct output_geometry_value<GeometryOut, true>
  359. : tupled_range_values<GeometryOut>
  360. {};
  361. template
  362. <
  363. typename GeometryOut,
  364. bool IsTupled = is_tupled_output<GeometryOut>::value
  365. >
  366. struct output_geometry_back_inserter_
  367. {
  368. typedef geometry::range::back_insert_iterator<GeometryOut> type;
  369. static type apply(GeometryOut & out)
  370. {
  371. return geometry::range::back_inserter(out);
  372. }
  373. };
  374. template <typename GeometryOut>
  375. struct output_geometry_back_inserter_<GeometryOut, true>
  376. : tupled_back_inserters<GeometryOut>
  377. {};
  378. template <typename GeometryOut>
  379. inline typename output_geometry_back_inserter_<GeometryOut>::type
  380. output_geometry_back_inserter(GeometryOut & out)
  381. {
  382. return output_geometry_back_inserter_<GeometryOut>::apply(out);
  383. }
  384. // is_tag_same_as_pred
  385. // Defines a predicate true if type's tag is the same as Tag
  386. template <typename Tag>
  387. struct is_tag_same_as_pred
  388. {
  389. template <typename T>
  390. struct pred
  391. : boost::is_same<typename geometry::tag<T>::type, Tag>
  392. {};
  393. };
  394. // Allows to access a type/object in a pair/tuple corresponding to an index in
  395. // GeometryOut pair/tuple of a geometry defined by Tag.
  396. // If GeometryOut is a geometry then it's expected to be defined by DefaultTag.
  397. template
  398. <
  399. typename GeometryOut,
  400. typename Tag,
  401. typename DefaultTag,
  402. typename GeometryTag = typename geometry::tag<GeometryOut>::type
  403. >
  404. struct output_geometry_access
  405. {};
  406. // assume GeometryTag is void because not adapted tuple holding geometries was passed
  407. template <typename TupledOut, typename Tag, typename DefaultTag>
  408. struct output_geometry_access<TupledOut, Tag, DefaultTag, void>
  409. {
  410. static const int index = geometry::tuples::find_index_if
  411. <
  412. TupledOut, is_tag_same_as_pred<Tag>::template pred
  413. >::value;
  414. typedef typename geometry::tuples::element<index, TupledOut>::type type;
  415. template <typename Tuple>
  416. static typename geometry::tuples::element<index, Tuple>::type&
  417. get(Tuple & tup)
  418. {
  419. return geometry::tuples::get<index>(tup);
  420. }
  421. };
  422. template <typename GeometryOut, typename Tag, typename DefaultTag>
  423. struct output_geometry_access<GeometryOut, Tag, DefaultTag, DefaultTag>
  424. {
  425. typedef GeometryOut type;
  426. template <typename T>
  427. static T& get(T & v)
  428. {
  429. return v;
  430. }
  431. };
  432. } // namespace detail
  433. #endif // DOXYGEN_NO_DETAIL
  434. }} // namespace boost::geometry
  435. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP