Loading...
Searching...
No Matches
iterator_factory.cuh
1/*
2 * Copyright (c) 2022, NVIDIA CORPORATION.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <cuspatial/detail/functors.cuh>
20#include <cuspatial/error.hpp>
23#include <cuspatial/traits.hpp>
24
25#include <thrust/binary_search.h>
26#include <thrust/detail/raw_reference_cast.h>
27#include <thrust/iterator/counting_iterator.h>
28#include <thrust/iterator/permutation_iterator.h>
29#include <thrust/iterator/transform_iterator.h>
30#include <thrust/iterator/transform_output_iterator.h>
31#include <thrust/iterator/zip_iterator.h>
32#include <thrust/tuple.h>
33#include <thrust/type_traits/is_contiguous_iterator.h>
34
35#include <type_traits>
36
37namespace cuspatial {
38namespace detail {
39
44template <typename IndexType, typename UnaryFunction>
45inline CUSPATIAL_HOST_DEVICE auto make_counting_transform_iterator(IndexType start, UnaryFunction f)
46{
47 return thrust::make_transform_iterator(thrust::make_counting_iterator(start), f);
48}
49
54template <typename T, typename VectorType = vec_2d<T>>
56 __device__ VectorType operator()(thrust::tuple<T, T> const& pos)
57 {
58 return VectorType{thrust::get<0>(pos), thrust::get<1>(pos)};
59 }
60};
61
66template <typename T, typename VectorType = vec_2d<T>>
68 __device__ thrust::tuple<T, T> operator()(VectorType const& xy)
69 {
70 return thrust::make_tuple(xy.x, xy.y);
71 }
72};
73
78template <typename T, typename Box = box<T>>
80 __device__ thrust::tuple<T, T, T, T> operator()(Box const& box)
81 {
82 return thrust::make_tuple(box.v1.x, box.v1.y, box.v2.x, box.v2.y);
83 }
84};
85
90template <typename T, typename Vertex = vec_2d<T>>
92 __device__ box<T, Vertex> operator()(thrust::tuple<Vertex, Vertex> pair)
93 {
94 auto v1 = thrust::get<0>(pair);
95 auto v2 = thrust::get<1>(pair);
96 return {v1, v2};
97 }
98};
99
110template <typename Iter, typename Enable = void>
112 using element_t = typename std::iterator_traits<Iter>::value_type;
113 using value_type = vec_2d<element_t>;
114 Iter it;
115 constexpr interleaved_to_vec_2d(Iter it) : it{it} {}
116
117 CUSPATIAL_HOST_DEVICE value_type operator()(std::size_t i)
118 {
119 return vec_2d<element_t>{it[2 * i], it[2 * i + 1]};
120 }
121};
122
132template <typename Iter>
134 typename std::enable_if_t<thrust::is_contiguous_iterator_v<Iter>>> {
135 using element_t = typename std::iterator_traits<Iter>::value_type;
136 using value_type = vec_2d<element_t>;
137
138 element_t const* ptr;
139
140 constexpr interleaved_to_vec_2d(Iter it) : ptr{&thrust::raw_reference_cast(*it)}
141 {
142 CUSPATIAL_EXPECTS(!((intptr_t)ptr % alignof(vec_2d<element_t>)),
143 "Misaligned interleaved data.");
144 }
145
146 CUSPATIAL_HOST_DEVICE value_type operator()(std::size_t i)
147 {
148 auto const aligned =
149 static_cast<element_t const*>(__builtin_assume_aligned(ptr + 2 * i, 2 * sizeof(element_t)));
150 return vec_2d<element_t>{aligned[0], aligned[1]};
151 }
152};
153
158template <int stride>
160 auto __device__ operator()(std::size_t i) { return i * stride; }
161};
162
167template <class IndexT, class GeometryIter>
169 GeometryIter geometry_begin;
170 GeometryIter geometry_end;
171
172 index_to_geometry_id(GeometryIter begin, GeometryIter end)
173 : geometry_begin(begin), geometry_end(end)
174 {
175 }
176
177 CUSPATIAL_HOST_DEVICE auto operator()(IndexT idx)
178 {
179 return thrust::distance(geometry_begin,
180 thrust::upper_bound(thrust::seq, geometry_begin, geometry_end, idx));
181 }
182};
183
184} // namespace detail
185
211template <typename FirstIter, typename SecondIter>
212auto make_vec_2d_iterator(FirstIter first, SecondIter second)
213{
214 using T = typename std::iterator_traits<FirstIter>::value_type;
215 static_assert(is_same<T, iterator_value_type<SecondIter>>(), "Iterator value_type mismatch");
216
217 auto zipped = thrust::make_zip_iterator(first, second);
218 return thrust::make_transform_iterator(zipped, detail::tuple_to_vec_2d<T>());
219}
220
230template <typename Iter>
231auto make_vec_2d_iterator(Iter xy_begin)
232{
233 return detail::make_counting_transform_iterator(0, detail::interleaved_to_vec_2d<Iter>{xy_begin});
234}
235
257template <typename FirstIter, typename SecondIter>
258auto make_vec_2d_output_iterator(FirstIter first, SecondIter second)
259{
260 using T = typename std::iterator_traits<FirstIter>::value_type;
261 auto zipped_out = thrust::make_zip_iterator(thrust::make_tuple(first, second));
262 return thrust::transform_output_iterator(zipped_out, detail::vec_2d_to_tuple<T>());
263}
264
273template <typename Iter>
274auto make_vec_2d_output_iterator(Iter d_points_begin)
275{
276 using T = typename std::iterator_traits<Iter>::value_type;
277 auto fixed_stride_2_functor = detail::strided_functor<2>();
278 auto even_positions = thrust::make_permutation_iterator(
279 d_points_begin, detail::make_counting_transform_iterator(0, fixed_stride_2_functor));
280 auto odd_positions = thrust::make_permutation_iterator(
281 thrust::next(d_points_begin),
282 detail::make_counting_transform_iterator(0, fixed_stride_2_functor));
283 auto zipped_outputs =
284 thrust::make_zip_iterator(thrust::make_tuple(even_positions, odd_positions));
285 return thrust::make_transform_output_iterator(zipped_outputs, detail::vec_2d_to_tuple<T>());
286}
287
307template <typename FirstIter, typename SecondIter>
308auto make_box_iterator(FirstIter first, SecondIter second)
309{
310 using Vertex = typename cuspatial::iterator_value_type<FirstIter>;
311 using T = typename Vertex::value_type;
312
313 static_assert(is_same<Vertex, cuspatial::iterator_value_type<SecondIter>>(),
314 "Iterator value_type mismatch");
315
316 auto zipped = thrust::make_zip_iterator(first, second);
317 return thrust::make_transform_iterator(zipped, detail::vec_2d_tuple_to_box<T>());
318}
319
347template <typename MinXIter, typename MinYIter, typename MaxXIter, typename MaxYIter>
348auto make_box_output_iterator(MinXIter min_x, MinYIter min_y, MaxXIter max_x, MaxYIter max_y)
349{
350 using T = typename std::iterator_traits<MinXIter>::value_type;
351 auto zipped_out = thrust::make_zip_iterator(min_x, min_y, max_x, max_y);
352 return thrust::transform_output_iterator(zipped_out, detail::box_to_tuple<T>());
353}
354
379template <typename IndexT, typename GeometryIter>
380auto make_geometry_id_iterator(GeometryIter offsets_begin, GeometryIter offsets_end)
381{
382 return detail::make_counting_transform_iterator(
383 IndexT{0}, detail::index_to_geometry_id<IndexT, GeometryIter>{offsets_begin, offsets_end});
384}
385
414template <typename IndexT, typename GeometryIter, typename PartIter>
415auto make_geometry_id_iterator(GeometryIter geometry_offsets_begin,
416 GeometryIter geometry_offsets_end,
417 PartIter part_offsets_begin)
418{
419 auto first_part_offsets_begin =
420 thrust::make_permutation_iterator(part_offsets_begin, geometry_offsets_begin);
421
422 return make_geometry_id_iterator<IndexT>(
423 first_part_offsets_begin,
424 thrust::next(first_part_offsets_begin,
425 std::distance(geometry_offsets_begin, geometry_offsets_end)));
426}
427
428template <typename OffsetIterator>
429auto make_count_iterator_from_offset_iterator(OffsetIterator it)
430{
431 auto zipped_offsets_it = thrust::make_zip_iterator(it, thrust::next(it));
432 return thrust::make_transform_iterator(zipped_offsets_it, detail::offset_pair_to_count_functor{});
433}
434
439} // namespace cuspatial
A generic axis-aligned box type.
Definition box.hpp:35
#define CUSPATIAL_EXPECTS(cond, reason)
Macro for checking (pre-)conditions that throws an exception when a condition is violated.
Definition error.hpp:76
auto make_box_iterator(FirstIter first, SecondIter second)
Create an iterator to box data from two input iterators of vec_2d.
auto make_geometry_id_iterator(GeometryIter offsets_begin, GeometryIter offsets_end)
Create an input iterator that generates zero-based sequential geometry IDs for each element based on ...
auto make_vec_2d_iterator(FirstIter first, SecondIter second)
Create an iterator to vec_2d data from two input iterators.
auto make_vec_2d_output_iterator(FirstIter first, SecondIter second)
Create an output iterator to vec_2d data from two output iterators.
auto make_box_output_iterator(MinXIter min_x, MinYIter min_y, MaxXIter max_x, MaxYIter max_y)
Create an output iterator to box data from multiple output iterators.