File indexing completed on 2026-05-27 07:24:04
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011
0012 #include "detray/definitions/containers.hpp"
0013 #include "detray/definitions/detail/qualifiers.hpp"
0014 #include "detray/utils/ranges/empty.hpp"
0015 #include "detray/utils/ranges/ranges.hpp"
0016 #include "detray/utils/type_traits.hpp"
0017
0018
0019 #include <type_traits>
0020
0021 namespace detray::ranges {
0022
0023 namespace detail {
0024
0025 template <detray::ranges::range T>
0026 struct join_iterator;
0027
0028 }
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 template <detray::ranges::range range_t>
0042 struct join_view : public detray::ranges::view_interface<join_view<range_t>> {
0043
0044 using outer_iterator_t = detray::ranges::iterator_t<range_t>;
0045
0046 using outer_value_t =
0047 std::conditional_t<std::is_const_v<range_t>,
0048 const detray::ranges::range_value_t<range_t>,
0049 detray::ranges::range_value_t<range_t>>;
0050
0051 using inner_iterator_t = detray::ranges::iterator_t<outer_value_t>;
0052
0053 using iterator_t = detray::ranges::detail::join_iterator<range_t>;
0054 using value_t = std::iter_value_t<iterator_t>;
0055
0056
0057 constexpr join_view() = default;
0058
0059
0060 template <detray::ranges::range R>
0061 requires(!std::same_as<R, join_view>)
0062 DETRAY_HOST_DEVICE constexpr explicit join_view(R &&ranges)
0063 : m_begin{detray::ranges::begin(ranges)},
0064 m_end{detray::ranges::end(ranges)} {}
0065
0066
0067 DETRAY_HOST_DEVICE
0068 constexpr auto begin() const -> iterator_t { return {m_begin, m_end}; }
0069
0070
0071 DETRAY_HOST_DEVICE
0072 constexpr auto end() const -> iterator_t { return {m_end, m_end}; }
0073
0074
0075
0076 DETRAY_HOST_DEVICE
0077 constexpr auto data() const -> const value_t * { return &(*(*m_begin)); }
0078
0079
0080
0081 DETRAY_HOST_DEVICE
0082 constexpr auto data() -> value_t * { return &(*(*m_begin)); }
0083
0084
0085 DETRAY_HOST_DEVICE
0086 constexpr auto size() const noexcept -> std::size_t {
0087 std::size_t size{0u};
0088 for (outer_iterator_t itr = m_begin; itr != m_end; ++itr) {
0089
0090 const auto begin = detray::ranges::begin(*itr);
0091 const auto end = detray::ranges::end(*itr);
0092 size += static_cast<std::size_t>(detray::ranges::distance(begin, end));
0093 }
0094 return size;
0095 }
0096
0097
0098 outer_iterator_t m_begin{};
0099 outer_iterator_t m_end{};
0100 };
0101
0102 namespace views {
0103
0104
0105 template <detray::ranges::range range_t>
0106 struct join : public ranges::join_view<range_t> {
0107 using base_type = detray::ranges::join_view<range_t>;
0108
0109 constexpr join() = default;
0110
0111 template <detray::ranges::range deduced_range_t>
0112 requires(!std::same_as<deduced_range_t, join>)
0113 DETRAY_HOST_DEVICE constexpr explicit join(deduced_range_t &&ranges)
0114 : base_type(std::forward<deduced_range_t>(ranges)) {}
0115
0116
0117 template <detray::ranges::range deduced_range_t>
0118 DETRAY_HOST_DEVICE constexpr auto operator()(deduced_range_t &&ranges) {
0119 return detray::ranges::join_view<deduced_range_t>(
0120 std::forward<deduced_range_t>(ranges));
0121 }
0122
0123
0124 DETRAY_HOST_DEVICE
0125 join &operator=(const join &other) {
0126 base_type::operator=(other);
0127 return *this;
0128 }
0129 };
0130
0131
0132 DETRAY_HOST_DEVICE join() -> join<detray::ranges::views::empty<dvector<int>>>;
0133
0134 template <detray::ranges::range R>
0135 DETRAY_HOST_DEVICE join(R &&ranges) -> join<std::remove_reference_t<R>>;
0136
0137 }
0138
0139 namespace detail {
0140
0141
0142
0143
0144
0145
0146
0147 template <detray::ranges::range range_t>
0148 struct join_iterator {
0149 using outer_iterator_t =
0150 std::conditional_t<std::is_const_v<range_t>,
0151 detray::ranges::const_iterator_t<range_t>,
0152 detray::ranges::iterator_t<range_t>>;
0153 using outer_value_t = decltype(*std::declval<outer_iterator_t>());
0154 using inner_iterator_t = std::conditional_t<
0155 std::is_same_v<outer_iterator_t,
0156 detray::ranges::const_iterator_t<range_t>>,
0157 detray::ranges::const_iterator_t<outer_value_t>,
0158 detray::ranges::iterator_t<outer_value_t>>;
0159
0160 using iterator_t = inner_iterator_t;
0161 using difference_type = std::iter_difference_t<iterator_t>;
0162 using value_type = std::iter_value_t<iterator_t>;
0163 using pointer = typename std::iterator_traits<iterator_t>::pointer;
0164 using reference = std::iter_reference_t<iterator_t>;
0165 using iterator_category =
0166 typename std::iterator_traits<iterator_t>::iterator_category;
0167
0168
0169 constexpr join_iterator() = default;
0170
0171
0172 DETRAY_HOST_DEVICE
0173 constexpr join_iterator(outer_iterator_t begin, outer_iterator_t end)
0174 : m_outer_begin(begin), m_outer_end(end), m_outer_itr(begin) {
0175 if (m_outer_itr != m_outer_end) {
0176 m_inner_itr = (*m_outer_itr).begin();
0177 } else {
0178 m_inner_itr = {};
0179 }
0180 next_inner();
0181 }
0182
0183
0184
0185 DETRAY_HOST_DEVICE auto operator++() -> join_iterator & {
0186 ++m_inner_itr;
0187 next_inner();
0188
0189 return *this;
0190 }
0191
0192 DETRAY_HOST_DEVICE constexpr auto operator++(int) -> join_iterator {
0193 auto tmp(*this);
0194 ++(*this);
0195 return tmp;
0196 }
0197
0198
0199
0200
0201 DETRAY_HOST_DEVICE constexpr auto operator--() -> join_iterator &
0202 requires std::bidirectional_iterator<inner_iterator_t> &&
0203 std::bidirectional_iterator<outer_iterator_t>
0204 {
0205
0206
0207 if (m_outer_itr == m_outer_end) {
0208 --m_outer_itr;
0209 }
0210
0211 previous_inner();
0212 --m_inner_itr;
0213
0214 return *this;
0215 }
0216
0217 DETRAY_HOST_DEVICE constexpr auto operator--(int) -> join_iterator
0218 requires std::bidirectional_iterator<inner_iterator_t> &&
0219 std::bidirectional_iterator<outer_iterator_t>
0220 {
0221 auto tmp(*this);
0222 --(*this);
0223 return tmp;
0224 }
0225
0226
0227
0228 DETRAY_HOST_DEVICE
0229 constexpr decltype(auto) operator*() const { return *m_inner_itr; }
0230
0231
0232 DETRAY_HOST_DEVICE constexpr auto operator+=(const difference_type j)
0233 -> join_iterator &
0234 requires std::random_access_iterator<inner_iterator_t> &&
0235 std::random_access_iterator<outer_iterator_t>
0236 {
0237
0238 if (difference_type i{j}; i >= difference_type{0}) {
0239 while (i--) {
0240 ++(*this);
0241 }
0242 } else {
0243 while (i++) {
0244 --(*this);
0245 }
0246 }
0247 return *this;
0248 }
0249
0250
0251 DETRAY_HOST_DEVICE constexpr auto operator-=(const difference_type j)
0252 -> join_iterator &
0253 requires std::random_access_iterator<inner_iterator_t> &&
0254 std::random_access_iterator<outer_iterator_t>
0255 {
0256 m_inner_itr += (-j);
0257 return *this;
0258 }
0259
0260
0261 DETRAY_HOST_DEVICE constexpr decltype(auto) operator[](
0262 const difference_type i) const
0263 requires std::random_access_iterator<inner_iterator_t> &&
0264 std::random_access_iterator<outer_iterator_t>
0265 {
0266 difference_type offset{i -
0267 (m_inner_itr - detray::ranges::begin(*m_outer_itr))};
0268 return *(*this + offset);
0269 }
0270
0271 private:
0272
0273 DETRAY_HOST_DEVICE friend constexpr bool operator==(
0274 const join_iterator &lhs, const join_iterator &rhs) {
0275 return (lhs.m_inner_itr == rhs.m_inner_itr);
0276 }
0277
0278
0279
0280 DETRAY_HOST_DEVICE friend constexpr bool operator!=(
0281 const join_iterator &lhs, const join_iterator &rhs) {
0282 return (lhs.m_outer_itr != rhs.m_outer_itr);
0283 }
0284
0285
0286 DETRAY_HOST_DEVICE friend constexpr auto operator<=>(const join_iterator &lhs,
0287 const join_iterator &rhs)
0288 requires detray::ranges::random_access_iterator<inner_iterator_t> &&
0289 std::random_access_iterator<outer_iterator_t>
0290 {
0291 #if defined(__apple_build_version__)
0292 const auto l_o_itr{lhs.m_outer_itr};
0293 const auto l_i_itr{lhs.m_inner_itr};
0294 const auto r_o_itr{rhs.m_outer_itr};
0295 const auto r_i_itr{rhs.m_inner_itr};
0296 if (l_o_itr == r_o_itr) {
0297 if (l_i_itr < r_i_itr || (l_i_itr == r_i_itr && l_i_itr < r_i_itr)) {
0298 return std::strong_ordering::less;
0299 }
0300 if (l_i_itr > r_i_itr || (l_i_itr == r_i_itr && l_i_itr > r_i_itr)) {
0301 return std::strong_ordering::greater;
0302 }
0303 return std::strong_ordering::equivalent;
0304 } else {
0305 if (l_o_itr < r_o_itr || (l_o_itr == r_o_itr && l_o_itr < r_o_itr)) {
0306 return std::strong_ordering::less;
0307 }
0308 if (l_o_itr > r_o_itr || (l_o_itr == r_o_itr && l_o_itr > r_o_itr)) {
0309 return std::strong_ordering::greater;
0310 }
0311 return std::strong_ordering::equivalent;
0312 }
0313 #else
0314 if (lhs.m_outer_itr == rhs.m_outer_itr) {
0315 return lhs.m_inner_itr <=> rhs.m_inner_itr;
0316 } else {
0317 return lhs.m_outer_itr <=> rhs.m_outer_itr;
0318 }
0319 #endif
0320 }
0321
0322
0323 DETRAY_HOST_DEVICE friend constexpr auto operator+(const join_iterator &itr,
0324 const difference_type j)
0325 -> join_iterator
0326 requires std::random_access_iterator<inner_iterator_t> &&
0327 std::random_access_iterator<outer_iterator_t>
0328 {
0329 join_iterator<range_t> tmp(itr);
0330
0331 if (difference_type i{j}; i >= difference_type{0}) {
0332 while (i--) {
0333 ++tmp;
0334 }
0335 } else {
0336 while (i++) {
0337 --tmp;
0338 }
0339 }
0340 return tmp;
0341 }
0342
0343 DETRAY_HOST_DEVICE friend constexpr auto operator+(const difference_type j,
0344 const join_iterator &itr)
0345 -> join_iterator
0346 requires std::random_access_iterator<inner_iterator_t> &&
0347 std::random_access_iterator<outer_iterator_t>
0348 {
0349 return itr + j;
0350 }
0351
0352
0353 DETRAY_HOST_DEVICE friend constexpr auto operator-(const join_iterator &itr,
0354 const difference_type j)
0355 -> join_iterator
0356 requires std::random_access_iterator<inner_iterator_t> &&
0357 std::random_access_iterator<outer_iterator_t>
0358 {
0359 return itr + (-j);
0360 }
0361
0362
0363 DETRAY_HOST_DEVICE friend constexpr auto operator-(const join_iterator &left,
0364 const join_iterator &right)
0365 -> difference_type
0366 requires std::random_access_iterator<inner_iterator_t> &&
0367 std::random_access_iterator<outer_iterator_t>
0368 {
0369 const join_iterator lhs{left};
0370 const join_iterator rhs{right};
0371 outer_iterator_t tmp_outer_itr;
0372
0373 if (tmp_outer_itr == rhs.m_outer_itr) {
0374 return lhs.m_inner_itr - rhs.m_inner_itr;
0375 }
0376 if ((tmp_outer_itr - rhs.m_outer_itr) < 0) {
0377
0378 difference_type diff{lhs.m_inner_itr -
0379 detray::ranges::end(*lhs.m_outer_itr)};
0380 for (tmp_outer_itr + 1; tmp_outer_itr != rhs.m_outer_itr;
0381 ++tmp_outer_itr) {
0382 diff += detray::ranges::end(*tmp_outer_itr) -
0383 detray::ranges::begin(*tmp_outer_itr);
0384 }
0385 diff += rhs.m_inner_itr - detray::ranges::end(*rhs.m_outer_itr);
0386 return diff;
0387 } else {
0388
0389 difference_type diff{lhs.m_inner_itr -
0390 detray::ranges::begin(*tmp_outer_itr)};
0391 for (tmp_outer_itr - 1; tmp_outer_itr != rhs.m_outer_itr;
0392 --tmp_outer_itr) {
0393 diff += detray::ranges::end(*tmp_outer_itr) -
0394 detray::ranges::begin(*tmp_outer_itr);
0395 }
0396 diff += rhs.m_inner_itr - detray::ranges::begin(*rhs.m_outer_itr);
0397 return diff;
0398 }
0399 }
0400
0401
0402 constexpr void next_inner() {
0403 if (m_outer_itr == m_outer_end) {
0404 return;
0405 }
0406 while (m_inner_itr == detray::ranges::end(*m_outer_itr)) {
0407 ++m_outer_itr;
0408 if (m_outer_itr != m_outer_end) {
0409 m_inner_itr = (*m_outer_itr).begin();
0410 } else {
0411 break;
0412 }
0413 }
0414 }
0415
0416
0417 constexpr void previous_inner() {
0418
0419 inner_iterator_t inner_begin = detray::ranges::begin(*m_outer_itr);
0420
0421
0422
0423
0424 while (m_inner_itr == inner_begin) {
0425
0426 if (m_outer_itr == m_outer_begin) {
0427 m_inner_itr = detray::ranges::end(*m_outer_begin);
0428 return;
0429 }
0430
0431 --m_outer_itr;
0432
0433 inner_begin = detray::ranges::begin(*m_outer_itr);
0434 m_inner_itr = detray::ranges::end(*m_outer_itr);
0435 }
0436 }
0437
0438
0439 outer_iterator_t m_outer_begin{};
0440 outer_iterator_t m_outer_end{};
0441
0442 outer_iterator_t m_outer_itr{};
0443
0444 inner_iterator_t m_inner_itr{};
0445 };
0446
0447 }
0448
0449 }