tupled_output.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  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/range/value_type.hpp>
  9. #include <boost/geometry/algorithms/convert.hpp>
  10. #include <boost/geometry/core/config.hpp>
  11. #include <boost/geometry/core/static_assert.hpp>
  12. #include <boost/geometry/core/tag.hpp>
  13. #include <boost/geometry/core/tag_cast.hpp>
  14. #include <boost/geometry/core/tags.hpp>
  15. #include <boost/geometry/geometries/concepts/check.hpp>
  16. #include <boost/geometry/util/range.hpp>
  17. #include <boost/geometry/util/tuples.hpp>
  18. #include <boost/geometry/util/type_traits.hpp>
  19. namespace boost { namespace geometry
  20. {
  21. #ifndef DOXYGEN_NO_DETAIL
  22. namespace detail
  23. {
  24. template <typename T, bool IsRange = range::detail::is_range<T>::value>
  25. struct is_tupled_output_element_base
  26. : util::bool_constant<false>
  27. {};
  28. template <typename T>
  29. struct is_tupled_output_element_base<T, true>
  30. : util::bool_constant
  31. <
  32. (util::is_multi<T>::value
  33. ||
  34. (util::is_not_geometry<T>::value
  35. &&
  36. util::is_multi_element
  37. <
  38. typename boost::range_value<T>::type
  39. >::value))
  40. >
  41. {};
  42. // true if T is a multi-geometry or is a range of points, linestrings or
  43. // polygons
  44. template <typename T>
  45. struct is_tupled_output_element
  46. : is_tupled_output_element_base<T>
  47. {};
  48. // true if Output is not a geometry (so e.g. tuple was not adapted to any
  49. // concept) and at least one of the tuple elements is a multi-geometry or
  50. // a range of points, linestrings or polygons
  51. template <typename Output>
  52. struct is_tupled_output_check
  53. : util::bool_constant
  54. <
  55. (util::is_not_geometry<Output>::value
  56. && geometry::tuples::exists_if<Output, is_tupled_output_element>::value)
  57. >
  58. {};
  59. // true if T is not a geometry (so e.g. tuple was not adapted to any
  60. // concept) and at least one of the tuple elements is a point, linesting
  61. // or polygon
  62. template <typename T>
  63. struct is_tupled_single_output_check
  64. : util::bool_constant
  65. <
  66. (util::is_not_geometry<T>::value
  67. && geometry::tuples::exists_if<T, util::is_multi_element>::value)
  68. >
  69. {};
  70. // true if Output is boost::tuple, boost::tuples::cons, std::pair or std::tuple
  71. // and is_tupled_output_check defiend above passes
  72. template <typename Output, bool IsTupled = tuples::is_tuple<Output>::value>
  73. struct is_tupled_output
  74. : util::bool_constant<false>
  75. {};
  76. template <typename Output>
  77. struct is_tupled_output<Output, true>
  78. : is_tupled_output_check<Output>
  79. {};
  80. // true if T is boost::tuple, boost::tuples::cons, std::pair or std::tuple
  81. // and is_tupled_single_output_check defiend above passes
  82. template <typename T, bool IsTupled = tuples::is_tuple<T>::value>
  83. struct is_tupled_single_output
  84. : util::bool_constant<false>
  85. {};
  86. template <typename T>
  87. struct is_tupled_single_output<T, true>
  88. : is_tupled_single_output_check<T>
  89. {};
  90. template <typename Tag>
  91. struct tupled_output_find_index_pred
  92. {
  93. template <typename T>
  94. struct pred
  95. : std::is_same<typename geometry::tag<T>::type, Tag>
  96. {};
  97. };
  98. // Valid only if tupled_output_has<Output, Tag> is true
  99. template <typename Output, typename Tag>
  100. struct tupled_output_find_index
  101. : geometry::tuples::find_index_if
  102. <
  103. Output,
  104. tupled_output_find_index_pred<Tag>::template pred
  105. >
  106. {};
  107. template
  108. <
  109. typename Output,
  110. typename Tag,
  111. bool IsTupledOutput = is_tupled_output<Output>::value
  112. >
  113. struct tupled_output_has
  114. : util::bool_constant<false>
  115. {};
  116. template <typename Output, typename Tag>
  117. struct tupled_output_has<Output, Tag, true>
  118. : util::bool_constant
  119. <
  120. ((tupled_output_find_index<Output, Tag>::value)
  121. < (geometry::tuples::size<Output>::value))
  122. >
  123. {};
  124. // Valid only if tupled_output_has<Output, Tag> is true
  125. template <typename Tag, typename Output>
  126. inline typename geometry::tuples::element
  127. <
  128. tupled_output_find_index<Output, Tag>::value,
  129. Output
  130. >::type &
  131. tupled_output_get(Output & output)
  132. {
  133. return geometry::tuples::get<tupled_output_find_index<Output, Tag>::value>(output);
  134. }
  135. // defines a tuple-type holding value-types of ranges being elements of
  136. // Output pair/tuple
  137. template <typename Tuple>
  138. struct tupled_range_values;
  139. template <typename ...Ts>
  140. struct tupled_range_values<std::tuple<Ts...> >
  141. {
  142. typedef std::tuple<typename boost::range_value<Ts>::type...> type;
  143. };
  144. template <typename F, typename S>
  145. struct tupled_range_values<std::pair<F, S> >
  146. {
  147. typedef std::pair
  148. <
  149. typename boost::range_value<F>::type,
  150. typename boost::range_value<S>::type
  151. > type;
  152. };
  153. template
  154. <
  155. typename Tuple,
  156. size_t I = 0,
  157. size_t N = boost::tuples::length<Tuple>::value
  158. >
  159. struct tupled_range_values_bt
  160. {
  161. typedef boost::tuples::cons
  162. <
  163. typename boost::range_value
  164. <
  165. typename boost::tuples::element<I, Tuple>::type
  166. >::type,
  167. typename tupled_range_values_bt<Tuple, I+1, N>::type
  168. > type;
  169. };
  170. template <typename Tuple, size_t N>
  171. struct tupled_range_values_bt<Tuple, N, N>
  172. {
  173. typedef boost::tuples::null_type type;
  174. };
  175. template <typename ...Ts>
  176. struct tupled_range_values<boost::tuples::tuple<Ts...>>
  177. : tupled_range_values_bt<boost::tuples::tuple<Ts...>>
  178. {};
  179. template <typename HT, typename TT>
  180. struct tupled_range_values<boost::tuples::cons<HT, TT>>
  181. : tupled_range_values_bt<boost::tuples::cons<HT, TT>>
  182. {};
  183. // util defining a type and creating a tuple holding back-insert-iterators to
  184. // ranges being elements of Output pair/tuple
  185. template <typename Tuple>
  186. struct tupled_back_inserters;
  187. template <typename Is, typename Tuple>
  188. struct tupled_back_inserters_st;
  189. template <std::size_t ...Is, typename ...Ts>
  190. struct tupled_back_inserters_st<std::index_sequence<Is...>, std::tuple<Ts...> >
  191. {
  192. typedef std::tuple<geometry::range::back_insert_iterator<Ts>...> type;
  193. static type apply(std::tuple<Ts...> & tup)
  194. {
  195. return type(geometry::range::back_inserter(std::get<Is>(tup))...);
  196. }
  197. };
  198. template <typename ...Ts>
  199. struct tupled_back_inserters<std::tuple<Ts...> >
  200. : tupled_back_inserters_st
  201. <
  202. std::make_index_sequence<sizeof...(Ts)>,
  203. std::tuple<Ts...>
  204. >
  205. {};
  206. template <typename F, typename S>
  207. struct tupled_back_inserters<std::pair<F, S> >
  208. {
  209. typedef std::pair
  210. <
  211. geometry::range::back_insert_iterator<F>,
  212. geometry::range::back_insert_iterator<S>
  213. > type;
  214. static type apply(std::pair<F, S> & p)
  215. {
  216. return type(geometry::range::back_inserter(p.first),
  217. geometry::range::back_inserter(p.second));
  218. }
  219. };
  220. template <typename Tuple,
  221. size_t I = 0,
  222. size_t N = boost::tuples::length<Tuple>::value>
  223. struct tupled_back_inserters_bt
  224. {
  225. typedef boost::tuples::cons
  226. <
  227. geometry::range::back_insert_iterator
  228. <
  229. typename boost::tuples::element<I, Tuple>::type
  230. >,
  231. typename tupled_back_inserters_bt<Tuple, I+1, N>::type
  232. > type;
  233. static type apply(Tuple & tup)
  234. {
  235. return type(geometry::range::back_inserter(boost::get<I>(tup)),
  236. tupled_back_inserters_bt<Tuple, I+1, N>::apply(tup));
  237. }
  238. };
  239. template <typename Tuple, size_t N>
  240. struct tupled_back_inserters_bt<Tuple, N, N>
  241. {
  242. typedef boost::tuples::null_type type;
  243. static type apply(Tuple const&)
  244. {
  245. return type();
  246. }
  247. };
  248. template <typename ...Ts>
  249. struct tupled_back_inserters<boost::tuples::tuple<Ts...>>
  250. : tupled_back_inserters_bt<boost::tuples::tuple<Ts...>>
  251. {};
  252. template <typename HT, typename TT>
  253. struct tupled_back_inserters<boost::tuples::cons<HT, TT>>
  254. : tupled_back_inserters_bt<boost::tuples::cons<HT, TT>>
  255. {};
  256. template
  257. <
  258. typename GeometryOut,
  259. bool IsTupled = is_tupled_output<GeometryOut>::value
  260. >
  261. struct output_geometry_value
  262. : boost::range_value<GeometryOut>
  263. {};
  264. template <typename GeometryOut>
  265. struct output_geometry_value<GeometryOut, true>
  266. : tupled_range_values<GeometryOut>
  267. {};
  268. template
  269. <
  270. typename GeometryOut,
  271. bool IsTupled = is_tupled_output<GeometryOut>::value
  272. >
  273. struct output_geometry_back_inserter_
  274. {
  275. typedef geometry::range::back_insert_iterator<GeometryOut> type;
  276. static type apply(GeometryOut & out)
  277. {
  278. return geometry::range::back_inserter(out);
  279. }
  280. };
  281. template <typename GeometryOut>
  282. struct output_geometry_back_inserter_<GeometryOut, true>
  283. : tupled_back_inserters<GeometryOut>
  284. {};
  285. template <typename GeometryOut>
  286. inline typename output_geometry_back_inserter_<GeometryOut>::type
  287. output_geometry_back_inserter(GeometryOut & out)
  288. {
  289. return output_geometry_back_inserter_<GeometryOut>::apply(out);
  290. }
  291. // is_tag_same_as_pred
  292. // Defines a predicate true if type's tag is the same as Tag
  293. template <typename Tag>
  294. struct is_tag_same_as_pred
  295. {
  296. template <typename T>
  297. struct pred
  298. : std::is_same<typename geometry::tag<T>::type, Tag>
  299. {};
  300. };
  301. // Allows to access a type/object in a pair/tuple corresponding to an index in
  302. // GeometryOut pair/tuple of a geometry defined by Tag.
  303. // If GeometryOut is a geometry then it's expected to be defined by DefaultTag.
  304. template
  305. <
  306. typename GeometryOut,
  307. typename Tag,
  308. typename DefaultTag,
  309. typename GeometryTag = typename geometry::tag<GeometryOut>::type
  310. >
  311. struct output_geometry_access
  312. {};
  313. // assume GeometryTag is void because not adapted tuple holding geometries was passed
  314. template <typename TupledOut, typename Tag, typename DefaultTag>
  315. struct output_geometry_access<TupledOut, Tag, DefaultTag, void>
  316. {
  317. static const int index = geometry::tuples::find_index_if
  318. <
  319. TupledOut, is_tag_same_as_pred<Tag>::template pred
  320. >::value;
  321. typedef typename geometry::tuples::element<index, TupledOut>::type type;
  322. template <typename Tuple>
  323. static typename geometry::tuples::element<index, Tuple>::type&
  324. get(Tuple & tup)
  325. {
  326. return geometry::tuples::get<index>(tup);
  327. }
  328. };
  329. template <typename GeometryOut, typename Tag, typename DefaultTag>
  330. struct output_geometry_access<GeometryOut, Tag, DefaultTag, DefaultTag>
  331. {
  332. typedef GeometryOut type;
  333. template <typename T>
  334. static T& get(T & v)
  335. {
  336. return v;
  337. }
  338. };
  339. template <typename Geometry>
  340. struct output_geometry_concept_check
  341. {
  342. static void apply()
  343. {
  344. concepts::check<Geometry>();
  345. }
  346. };
  347. template <typename First, typename Second>
  348. struct output_geometry_concept_check<std::pair<First, Second> >
  349. {
  350. static void apply()
  351. {
  352. concepts::check<First>();
  353. concepts::check<Second>();
  354. }
  355. };
  356. template <typename Tuple,
  357. size_t I = 0,
  358. size_t N = geometry::tuples::size<Tuple>::value>
  359. struct output_geometry_concept_check_t
  360. {
  361. static void apply()
  362. {
  363. concepts::check<typename geometry::tuples::element<I, Tuple>::type>();
  364. output_geometry_concept_check_t<Tuple, I + 1, N>::apply();
  365. }
  366. };
  367. template <typename Tuple, size_t N>
  368. struct output_geometry_concept_check_t<Tuple, N, N>
  369. {
  370. static void apply()
  371. {}
  372. };
  373. template <typename ...Ts>
  374. struct output_geometry_concept_check<std::tuple<Ts...> >
  375. : output_geometry_concept_check_t<std::tuple<Ts...> >
  376. {};
  377. template <typename ...Ts>
  378. struct output_geometry_concept_check<boost::tuple<Ts...> >
  379. : output_geometry_concept_check_t<boost::tuple<Ts...> >
  380. {};
  381. template <typename HT, typename TT>
  382. struct output_geometry_concept_check<boost::tuples::cons<HT, TT> >
  383. : output_geometry_concept_check_t<boost::tuples::cons<HT, TT> >
  384. {};
  385. struct tupled_output_tag {};
  386. template <typename GeometryOut>
  387. struct setop_insert_output_tag
  388. : std::conditional
  389. <
  390. geometry::detail::is_tupled_single_output<GeometryOut>::value,
  391. tupled_output_tag,
  392. typename geometry::tag<GeometryOut>::type
  393. >
  394. {};
  395. template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound, typename Tag>
  396. struct expect_output_assert_base;
  397. template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
  398. struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, pointlike_tag>
  399. {
  400. BOOST_GEOMETRY_STATIC_ASSERT(
  401. IsFound,
  402. "PointLike Geometry expected in tupled output.",
  403. Geometry1, Geometry2, TupledOut);
  404. };
  405. template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
  406. struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, linear_tag>
  407. {
  408. BOOST_GEOMETRY_STATIC_ASSERT(
  409. IsFound,
  410. "Linear Geometry expected in tupled output.",
  411. Geometry1, Geometry2, TupledOut);
  412. };
  413. template <typename Geometry1, typename Geometry2, typename TupledOut, bool IsFound>
  414. struct expect_output_assert_base<Geometry1, Geometry2, TupledOut, IsFound, areal_tag>
  415. {
  416. BOOST_GEOMETRY_STATIC_ASSERT(
  417. IsFound,
  418. "Areal Geometry expected in tupled output.",
  419. Geometry1, Geometry2, TupledOut);
  420. };
  421. template <typename Geometry1, typename Geometry2, typename TupledOut, typename Tag>
  422. struct expect_output_assert
  423. : expect_output_assert_base
  424. <
  425. Geometry1, Geometry2, TupledOut,
  426. geometry::tuples::exists_if
  427. <
  428. TupledOut,
  429. is_tag_same_as_pred<Tag>::template pred
  430. >::value,
  431. typename geometry::tag_cast
  432. <
  433. Tag, pointlike_tag, linear_tag, areal_tag
  434. >::type
  435. >
  436. {};
  437. template <typename Geometry1, typename Geometry2, typename TupledOut>
  438. struct expect_output_assert<Geometry1, Geometry2, TupledOut, void>
  439. {};
  440. template
  441. <
  442. typename Geometry1, typename Geometry2, typename TupledOut,
  443. typename ...Tags
  444. >
  445. struct expect_output
  446. : expect_output_assert<Geometry1, Geometry2, TupledOut, Tags>...
  447. {};
  448. template <typename CastedTag>
  449. struct single_tag_from_base_tag;
  450. template <>
  451. struct single_tag_from_base_tag<pointlike_tag>
  452. {
  453. typedef point_tag type;
  454. };
  455. template <>
  456. struct single_tag_from_base_tag<linear_tag>
  457. {
  458. typedef linestring_tag type;
  459. };
  460. template <>
  461. struct single_tag_from_base_tag<areal_tag>
  462. {
  463. typedef polygon_tag type;
  464. };
  465. template
  466. <
  467. typename Geometry,
  468. typename SingleOut,
  469. bool IsMulti = util::is_multi<Geometry>::value
  470. >
  471. struct convert_to_output
  472. {
  473. template <typename OutputIterator>
  474. static OutputIterator apply(Geometry const& geometry,
  475. OutputIterator oit)
  476. {
  477. SingleOut single_out;
  478. geometry::convert(geometry, single_out);
  479. *oit++ = single_out;
  480. return oit;
  481. }
  482. };
  483. template
  484. <
  485. typename Geometry,
  486. typename SingleOut
  487. >
  488. struct convert_to_output<Geometry, SingleOut, true>
  489. {
  490. template <typename OutputIterator>
  491. static OutputIterator apply(Geometry const& geometry,
  492. OutputIterator oit)
  493. {
  494. for (auto it = boost::begin(geometry); it != boost::end(geometry); ++it)
  495. {
  496. SingleOut single_out;
  497. geometry::convert(*it, single_out);
  498. *oit++ = single_out;
  499. }
  500. return oit;
  501. }
  502. };
  503. } // namespace detail
  504. #endif // DOXYGEN_NO_DETAIL
  505. }} // namespace boost::geometry
  506. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TUPLED_OUTPUT_HPP