• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.82
/libs/core/iterator_support/include/hpx/iterator_support/iterator_facade.hpp
1
//  Copyright (c) 2016 Thomas Heller
2
//  Copyright (c) 2016-2025 Hartmut Kaiser
3
//
4
//  SPDX-License-Identifier: BSL-1.0
5
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
6
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
//
8
//  This code is based on boost::iterators::iterator_facade
9
//  (C) Copyright David Abrahams 2002.
10
//  (C) Copyright Jeremy Siek    2002.
11
//  (C) Copyright Thomas Witt    2002.
12
//  (C) copyright Jeffrey Lee Hellrung, Jr. 2012.
13

14
#pragma once
15

16
#include <hpx/config.hpp>
17

18
#include <hpx/iterator_support/traits/is_iterator.hpp>
19
#include <hpx/modules/concepts.hpp>
20
#include <hpx/modules/type_support.hpp>
21

22
#include <cstddef>
23
#include <iterator>
24
#include <memory>
25
#include <type_traits>
26
#include <utility>
27

28
namespace hpx::util {
29

30
    ///////////////////////////////////////////////////////////////////////////
31
    // Helper class to gain access to the implementation functions in the
32
    // derived (user-defined) iterator classes.
33
    HPX_CXX_EXPORT class iterator_core_access
34
    {
35
    public:
36
        template <typename Iterator1, typename Iterator2>
37
        HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr bool
38
        equal(Iterator1 const& lhs, Iterator2 const& rhs) noexcept(noexcept(
39
            std::declval<Iterator1>().equal(std::declval<Iterator2>())))
4,757✔
40
        {
41
            return lhs.equal(rhs);
42
        }
43

44
        template <typename Iterator>
45
        HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr void increment(
46
            Iterator& it)
47
#if !defined(HPX_MSVC)
48
            // MSVC has issues with this
49
            noexcept(noexcept(std::declval<Iterator&>().increment()))
50
#endif
1,829✔
51
        {
52
            it.increment();
53
        }
54

55
        template <typename Iterator>
56
        HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr void decrement(
57
            Iterator& it)
58
#if !defined(HPX_MSVC)
59
            // MSVC has issues with this
60
            noexcept(noexcept(std::declval<Iterator&>().decrement()))
61
#endif
147✔
62
        {
63
            it.decrement();
64
        }
65

66
        template <typename Reference, typename Iterator>
67
        HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr Reference dereference(
68
            Iterator const& it)
69
#if !defined(HPX_MSVC)
70
            // MSVC has issues with this
71
            noexcept(noexcept(std::declval<Iterator>().dereference()))
72
#endif
12,960✔
73
        {
74
            return it.dereference();
75
        }
76

77
        template <typename Iterator, typename Distance>
78
        HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr void
79
        advance(Iterator& it, Distance n) noexcept(noexcept(
80
            std::declval<Iterator&>().advance(std::declval<Distance>())))
51✔
81
        {
82
            it.advance(n);
83
        }
84

85
        template <typename Iterator1, typename Iterator2>
86
        HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr
87
            typename std::iterator_traits<Iterator1>::difference_type
88
            distance_to(Iterator1 const& lhs, Iterator2 const& rhs) noexcept(
89
                noexcept(std::declval<Iterator1>().distance_to(
90
                    std::declval<Iterator2>())))
42✔
91
        {
92
            return lhs.distance_to(rhs);
93
        }
94
    };
95

96
    namespace detail {
97

98
        ///////////////////////////////////////////////////////////////////////
99
        template <typename Reference>
100
        struct arrow_dispatch    // proxy references
101
        {
102
            struct proxy
103
            {
104
                HPX_HOST_DEVICE
105
                explicit constexpr proxy(Reference const& x) noexcept
106
                  : ref_(x)
107
                {
108
                }
109

110
                HPX_HOST_DEVICE HPX_FORCEINLINE constexpr Reference*
111
                operator->() noexcept
112
                {
113
                    return std::addressof(ref_);
114
                }
115

116
                Reference ref_;
117
            };
118

119
            using type = proxy;
120

121
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr type call(
122
                Reference const& x) noexcept
123
            {
124
                return type(x);
125
            }
126
        };
127

128
        template <typename T>
129
        struct arrow_dispatch<T&>    // "real" references
130
        {
131
            using type = T*;
132

133
            HPX_HOST_DEVICE HPX_FORCEINLINE static constexpr type call(
134
                T& x) noexcept
135
            {
136
                return std::addressof(x);
137
            }
138
        };
139

140
        template <typename T>
141
        using arrow_dispatch_t = typename arrow_dispatch<T>::type;
142

143
        ///////////////////////////////////////////////////////////////////////
144
        // Implementation for input and forward iterators
145
        template <typename Derived, typename T, typename Category,
146
            typename Reference, typename Distance, typename Pointer>
147
        class iterator_facade_base
148
        {
149
        public:
150
            using iterator_category = Category;
151
            using value_type = std::remove_const_t<T>;
152
            using difference_type = Distance;
153
            using pointer = std::conditional_t<std::is_void_v<Pointer>,
154
                arrow_dispatch_t<Reference>, Pointer>;
155
            using reference = Reference;
156

157
            // NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
158
            HPX_HOST_DEVICE iterator_facade_base() = default;
159

160
        protected:
161
            HPX_HOST_DEVICE Derived& derived() noexcept
162
            {
163
                return *static_cast<Derived*>(this);
164
            }
165

166
            HPX_HOST_DEVICE constexpr Derived const& derived() const noexcept
167
            {
168
                return *static_cast<Derived const*>(this);
169
            }
29,994✔
170

171
        public:
172
            HPX_HOST_DEVICE constexpr decltype(auto) operator*() const
173
                noexcept(noexcept(iterator_core_access::dereference<reference>(
174
                    std::declval<Derived>())))
29,994✔
175
            {
176
                return iterator_core_access::dereference<reference>(
177
                    this->derived());
178
            }
179

180
            HPX_HOST_DEVICE constexpr pointer operator->() const
181
                noexcept(noexcept(iterator_core_access::dereference<reference>(
182
                    std::declval<Derived>())))
183
            {
184
                return arrow_dispatch<Reference>::call(*this->derived());
10,000✔
185
            }
186

187
            HPX_HOST_DEVICE Derived& operator++() noexcept(noexcept(
188
                iterator_core_access::increment(std::declval<Derived&>())))
189
            {
1,751✔
190
                Derived& this_ = this->derived();
191
                iterator_core_access::increment(this_);
192
                return this_;
193
            }
194
        };
195

196
        ////////////////////////////////////////////////////////////////////////
197
        // Implementation for bidirectional iterators
198
        template <typename Derived, typename T, typename Reference,
199
            typename Distance, typename Pointer>
200
        class iterator_facade_base<Derived, T, std::bidirectional_iterator_tag,
201
            Reference, Distance, Pointer>
202
          : public iterator_facade_base<Derived, T, std::forward_iterator_tag,
203
                Reference, Distance, Pointer>
204
        {
205
            using base_type = iterator_facade_base<Derived, T,
206
                std::forward_iterator_tag, Reference, Distance, Pointer>;
207

208
        public:
209
            using iterator_category = std::bidirectional_iterator_tag;
210
            using value_type = std::remove_const_t<T>;
211
            using difference_type = Distance;
212
            using pointer = std::conditional_t<std::is_void_v<Pointer>,
213
                arrow_dispatch_t<Reference>, Pointer>;
214
            using reference = Reference;
215

216
            HPX_HOST_DEVICE iterator_facade_base() = default;
217

218
            HPX_HOST_DEVICE Derived& operator--() noexcept(noexcept(
219
                iterator_core_access::decrement(std::declval<Derived&>())))
220
            {
145✔
221
                Derived& this_ = this->derived();
222
                iterator_core_access::decrement(this_);
223
                return this_;
224
            }
225

226
            HPX_HOST_DEVICE Derived operator--(int) noexcept(noexcept(
×
227
                iterator_core_access::decrement(std::declval<Derived&>())))
228
            {
229
                Derived result(this->derived());
230
                --*this;
231
                return result;
232
            }
233
        };
234

235
        ////////////////////////////////////////////////////////////////////////
236
        // Implementation for random access iterators
237

238
        // A proxy return type for operator[], needed to deal with iterators
239
        // that may invalidate references upon destruction. Consider the
240
        // temporary iterator in *(a + n)
241
        template <typename Iterator>
242
        class operator_brackets_proxy
243
        {
244
            // Iterator is actually an iterator_facade, so we do not have to
245
            // go through iterator_traits to access the traits.
246
            using reference = typename Iterator::reference;
247
            using value_type = typename Iterator::value_type;
248

249
        public:
250
            HPX_HOST_DEVICE explicit constexpr operator_brackets_proxy(
251
                Iterator const& iter) noexcept
252
              : iter_(iter)
253
            {
254
            }
255

256
            HPX_HOST_DEVICE constexpr operator reference() const
257
                noexcept(noexcept(*std::declval<Iterator>()))
258
            {
259
                return *iter_;
260
            }
261

262
            HPX_HOST_DEVICE operator_brackets_proxy& operator=(
263
                value_type const& val)
264
            {
265
                *iter_ = val;
266
                return *this;
267
            }
268

269
        private:
270
            Iterator iter_;
271
        };
272

273
        // We can force (not) using the operator_brackets_proxy by adding an
274
        // embedded type use_brackets_proxy to the iterator that evaluates to
275
        // either std::true_type of std::false_type.
276
        HPX_HAS_XXX_TRAIT_DEF(use_brackets_proxy)
277

278
        // A meta-function that determines whether operator[] must return a
279
        // proxy, or whether it can simply return a copy of the value_type.
280
        template <typename Iterator, typename Value, typename Enable = void>
281
        struct use_operator_brackets_proxy
282
          : std::integral_constant<bool,
283
                !(std::is_copy_constructible_v<Value> &&
284
                    std::is_const_v<Value>)>
285
        {
286
        };
287

288
        template <typename Iterator, typename Value>
289
        struct use_operator_brackets_proxy<Iterator, Value,
290
            std::enable_if_t<has_use_brackets_proxy_v<Iterator>>>
291
          : Iterator::use_brackets_proxy
292
        {
293
        };
294

295
        template <typename Iterator, typename Value>
296
        struct operator_brackets_result
297
        {
298
            using type = std::conditional_t<
299
                use_operator_brackets_proxy<Iterator, Value>::value,
300
                operator_brackets_proxy<Iterator>, Value>;
301
        };
302

303
        template <typename Iterator>
304
        HPX_HOST_DEVICE operator_brackets_proxy<Iterator>
305
        make_operator_brackets_result(Iterator const& iter, std::true_type)
306
        {
307
            return operator_brackets_proxy<Iterator>(iter);
308
        }
309

310
        template <typename Iterator>
311
        HPX_HOST_DEVICE typename Iterator::value_type
312
        make_operator_brackets_result(Iterator const& iter, std::false_type)
313
        {
314
            return *iter;
315
        }
316

317
        template <typename Derived, typename T, typename Reference,
318
            typename Distance, typename Pointer>
319
        class iterator_facade_base<Derived, T, std::random_access_iterator_tag,
320
            Reference, Distance, Pointer>
321
          : public iterator_facade_base<Derived, T,
322
                std::bidirectional_iterator_tag, Reference, Distance, Pointer>
323
        {
324
            using base_type = iterator_facade_base<Derived, T,
325
                std::bidirectional_iterator_tag, Reference, Distance, Pointer>;
326

327
        public:
328
            using iterator_category = std::random_access_iterator_tag;
329
            using value_type = std::remove_const_t<T>;
330
            using difference_type = Distance;
331
            using pointer = std::conditional_t<std::is_void_v<Pointer>,
332
                arrow_dispatch_t<Reference>, Pointer>;
7,484✔
333
            using reference = Reference;
334

335
            HPX_HOST_DEVICE iterator_facade_base() = default;
336

337
            HPX_HOST_DEVICE constexpr auto operator[](difference_type n) const
338
            {
85✔
339
                using use_proxy = use_operator_brackets_proxy<Derived, T>;
340

341
                return make_operator_brackets_result<Derived>(
342
                    this->derived() + n, use_proxy{});
343
            }
344

345
            HPX_HOST_DEVICE Derived& operator+=(difference_type n) noexcept(
346
                noexcept(iterator_core_access::advance(
347
                    std::declval<Derived&>(), std::declval<difference_type>())))
348
            {
349
                Derived& this_ = this->derived();
350
                iterator_core_access::advance(this_, n);
351
                return this_;
352
            }
353

354
            HPX_HOST_DEVICE constexpr Derived operator+(difference_type n) const
355
                noexcept(noexcept(iterator_core_access::advance(
356
                    std::declval<Derived&>(), std::declval<difference_type>())))
357
            {
358
                Derived result(this->derived());
359
                return result += n;
360
            }
361

362
            HPX_HOST_DEVICE Derived& operator-=(difference_type n) noexcept(
363
                noexcept(iterator_core_access::advance(std::declval<Derived&>(),
×
364
                    -std::declval<difference_type>())))
×
365
            {
366
                Derived& this_ = this->derived();
367
                iterator_core_access::advance(this_, -n);
368
                return this_;
369
            }
370

371
            HPX_HOST_DEVICE constexpr Derived operator-(difference_type n) const
372
                noexcept(noexcept(
373
                    iterator_core_access::advance(std::declval<Derived&>(),
374
                        -std::declval<difference_type>())))
375
            {
376
                Derived result(this->derived());
377
                return result -= n;
378
            }
379
        };
380
    }    // namespace detail
381

382
    ///////////////////////////////////////////////////////////////////////////
383
    HPX_CXX_EXPORT template <typename Derived, typename T, typename Category,
384
        typename Reference = T&, typename Distance = std::ptrdiff_t,
385
        typename Pointer = void>
386
    struct iterator_facade
387
      : detail::iterator_facade_base<Derived, T,
388
            // clang-format off
389
            decltype(traits::detail::coerce_iterator_tag(
390
                std::declval<Category>())),
391
            // clang-format on
392
            Reference, Distance, Pointer>
393
    {
394
    private:
395
        using base_type = detail::iterator_facade_base<Derived, T,
396
            // clang-format off
397
            decltype(traits::detail::coerce_iterator_tag(
398
                std::declval<Category>())),
399
            // clang-format on
400
            Reference, Distance, Pointer>;
401

402
    protected:
403
        // for convenience in derived classes
404
        using iterator_adaptor_ =
405
            iterator_facade<Derived, T, Category, Reference, Distance, Pointer>;
406

407
    public:
408
        using iterator_category = typename base_type::iterator_category;
409
        using value_type = typename base_type::value_type;
410
        using difference_type = typename base_type::difference_type;
411
        using pointer = typename base_type::pointer;
412
        using reference = typename base_type::reference;
413

414
        // NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
415
        HPX_HOST_DEVICE iterator_facade() = default;
416
    };
417

418
    namespace detail {
419

420
        // Iterators whose dereference operators reference the same value for
421
        // all iterators into the same sequence (like many input iterators) need
422
        // help with their postfix ++: the referenced value must be read and
423
        // stored away before the increment occurs so that *a++ yields the
424
        // originally referenced element and not the next one.
425
        template <typename Iterator>
426
        class postfix_increment_proxy
427
        {
428
            using value_type =
429
                typename std::iterator_traits<Iterator>::value_type;
430

431
        public:
432
            HPX_HOST_DEVICE explicit postfix_increment_proxy(Iterator const& x)
433
              : stored_value(*x)
434
            {
435
            }
436

437
            // Returning a mutable reference allows nonsense like
438
            // (*r++).mutate(), but it imposes fewer assumptions about the
439
            // behavior of the value_type. In particular, recall that
440
            // (*r).mutate() is legal if operator* returns by value.
441
            HPX_HOST_DEVICE value_type& operator*() const
442
            {
443
                return this->stored_value;
444
            }
445

446
        private:
447
            mutable std::remove_const_t<value_type> stored_value;
448
        };
449

450
        // In general, we can't determine that such an iterator isn't writable
451
        // -- we also need to store a copy of the old iterator so that it can
452
        // be written into.
453
        template <typename Iterator>
454
        class writable_postfix_increment_proxy
455
        {
456
            using value_type =
457
                typename std::iterator_traits<Iterator>::value_type;
458

459
        public:
460
            HPX_HOST_DEVICE
461
            explicit writable_postfix_increment_proxy(Iterator const& x)
462
              : stored_value(*x)
463
              , stored_iterator(x)
464
            {
465
            }
466

467
            // Dereferencing must return a proxy so that both *r++ = o and
468
            // value_type(*r++) can work.  In this case, *r is the same as *r++,
469
            // and the conversion operator below is used to ensure readability.
470
            HPX_HOST_DEVICE
471
            writable_postfix_increment_proxy const& operator*() const
472
            {
473
                return *this;
474
            }
475

476
            // Provides readability of *r++
477
            HPX_HOST_DEVICE operator value_type&() const
478
            {
479
                return stored_value;
480
            }
481

482
            // Provides writability of *r++
483
            template <typename T>
484
            HPX_HOST_DEVICE T const& operator=(T const& x) const
485
            {
486
                *this->stored_iterator = x;
487
                return x;    // NOLINT(bugprone-return-const-ref-from-parameter)
488
            }
489

490
            // This overload just in case only non-const objects are writable
491
            template <typename T>
492
            HPX_HOST_DEVICE T& operator=(T& x) const
493
            {
494
                *this->stored_iterator = x;
495
                return x;
496
            }
497
            // clang-format off
498
            // Provides X(r++)
499
            HPX_HOST_DEVICE operator Iterator const&() const
500
            {
501
                return stored_iterator;
502
            }
503
            // clang-format on
504

505
        private:
506
            mutable std::remove_const_t<value_type> stored_value;
507
            Iterator stored_iterator;
508
        };
509

510
        template <typename Reference, typename Value>
511
        struct is_non_proxy_reference
512
          : std::is_convertible<
513
                std::remove_reference_t<Reference> const volatile*,
514
                Value const volatile*>
515
        {
516
        };
517

518
        template <typename Reference, typename Value>
519
        inline constexpr bool is_non_proxy_reference_v =
520
            is_non_proxy_reference<Reference, Value>::value;
521

522
        // Because the C++98 input iterator requirements say that *r++ has type
523
        // T (value_type), implementations of some standard algorithms like
524
        // lexicographical_compare may use constructions like:
525
        //
526
        //          *r++ < *s++
527
        //
528
        // If *r++ returns a proxy (as required if r is writable but not
529
        // multi-pass), this sort of expression will fail unless the proxy
530
        // supports the operator<.  Since there are any number of such
531
        // operations, we're not going to try to support them.  Therefore,
532
        // even if r++ returns a proxy, *r++ will only return a proxy if *r also
533
        // returns a proxy.
534
        template <typename Iterator, typename Value, typename Reference,
535
            typename Enable = void>
536
        struct postfix_increment_result
537
        {
538
            using type = Iterator;
539
        };
540

541
        template <typename Iterator, typename Value, typename Reference>
542
        struct postfix_increment_result<Iterator, Value, Reference,
543
            std::enable_if_t<
544
                traits::has_category_v<Iterator, std::input_iterator_tag> &&
545
                is_non_proxy_reference_v<Reference, Value>>>
546
        {
547
            using type = postfix_increment_proxy<Iterator>;
548
        };
549

550
        template <typename Iterator, typename Value, typename Reference>
551
        struct postfix_increment_result<Iterator, Value, Reference,
552
            std::enable_if_t<
553
                traits::has_category_v<Iterator, std::input_iterator_tag> &&
554
                !is_non_proxy_reference_v<Reference, Value>>>
×
555
        {
556
            using type = writable_postfix_increment_proxy<Iterator>;
557
        };
558

559
        template <typename Iterator, typename Value, typename Reference>
560
        using postfix_increment_result_t =
561
            typename postfix_increment_result<Iterator, Value, Reference>::type;
562
    }    // namespace detail
563

564
    ///////////////////////////////////////////////////////////////////////////
565
    HPX_CXX_EXPORT template <typename Derived, typename T, typename Category,
566
        typename Reference, typename Distance, typename Pointer>
567
    HPX_HOST_DEVICE inline util::detail::postfix_increment_result_t<Derived,
568
        typename Derived::value_type, typename Derived::reference>
569
    operator++(
570
        iterator_facade<Derived, T, Category, Reference, Distance, Pointer>& i,
571
        int)
572
    {
573
        using iterator_type = util::detail::postfix_increment_result_t<Derived,
574
            typename Derived::value_type, typename Derived::reference>;
575

576
        iterator_type tmp(*static_cast<Derived*>(&i));
577
        ++i;
578
        return tmp;
579
    }
580

581
    namespace detail {
582

583
        template <typename Facade1, typename Facade2, typename Return,
584
            typename = std::void_t<decltype(iterator_core_access::equal(
585
                std::declval<Facade1>(), std::declval<Facade2>()))>>
586
        struct enable_operator_equal_interoperable
587
        {
588
            using type = Return;
589
        };
590

591
        template <typename Facade1, typename Facade2, typename Return,
592
            typename Cond>
593
        struct enable_operator_interoperable_ex
594
          : std::enable_if<Cond::value &&
595
                    (std::is_convertible_v<Facade1, Facade2> ||
596
                        std::is_convertible_v<Facade2, Facade1>),
597
                Return>
598
        {
599
        };
600
    }    // namespace detail
601

602
#define HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD(prefix, op, result_type)         \
603
    HPX_CXX_EXPORT template <typename Derived1, typename T1,                   \
604
        typename Category1, typename Reference1, typename Distance1,           \
605
        typename Pointer1, typename Derived2, typename T2, typename Category2, \
606
        typename Reference2, typename Distance2, typename Pointer2>            \
607
    HPX_HOST_DEVICE prefix                                                     \
608
        typename hpx::util::detail::enable_operator_equal_interoperable<       \
609
            Derived1, Derived2, result_type>::type                             \
610
        operator op(iterator_facade<Derived1, T1, Category1, Reference1,       \
611
                        Distance1, Pointer1> const& lhs,                       \
612
            iterator_facade<Derived2, T2, Category2, Reference2, Distance2,    \
613
                Pointer2> const& rhs) /**/
614

10,010✔
615
#define HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD_EX(                              \
616
    prefix, op, result_type, cond)                                             \
617
    HPX_CXX_EXPORT template <typename Derived1, typename T1,                   \
10,010✔
618
        typename Category1, typename Reference1, typename Distance1,           \
619
        typename Pointer1, typename Derived2, typename T2, typename Category2, \
620
        typename Reference2, typename Distance2, typename Pointer2>            \
621
    HPX_HOST_DEVICE prefix                                                     \
622
        typename hpx::util::detail::enable_operator_interoperable_ex<Derived1, \
623
            Derived2, result_type,                                             \
624
            cond<typename Derived1::iterator_category,                         \
625
                typename Derived2::iterator_category>>::type                   \
626
        operator op(iterator_facade<Derived1, T1, Category1, Reference1,       \
627
                        Distance1, Pointer1> const& lhs,                       \
628
            iterator_facade<Derived2, T2, Category2, Reference2, Distance2,    \
629
                Pointer2> const& rhs) /**/
630

631
    HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD(inline constexpr, ==, bool)
632
    {
633
        return iterator_core_access::equal(static_cast<Derived1 const&>(lhs),
634
            static_cast<Derived2 const&>(rhs));
635
    }
636

637
    HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD(inline constexpr, !=, bool)
638
    {
639
        return !iterator_core_access::equal(static_cast<Derived1 const&>(lhs),
640
            static_cast<Derived2 const&>(rhs));
641
    }
642

643
    namespace detail {
644

645
        template <typename Category1, typename Category2>
646
        struct enable_random_access_operations
647
          : std::integral_constant<bool,
648
                std::is_same_v<Category1, std::random_access_iterator_tag> &&
649
                    std::is_same_v<Category2, std::random_access_iterator_tag>>
650
        {
651
        };
652
    }    // namespace detail
653

654
    HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD_EX(
655
        constexpr, <, bool, detail::enable_random_access_operations)
656
    {
657
        return 0 <
658
            iterator_core_access::distance_to(static_cast<Derived1 const&>(lhs),
659
                static_cast<Derived2 const&>(rhs));
660
    }
661

662
    HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD_EX(
663
        constexpr, >, bool, detail::enable_random_access_operations)
664
    {
665
        return 0 >
666
            iterator_core_access::distance_to(static_cast<Derived1 const&>(lhs),
667
                static_cast<Derived2 const&>(rhs));
668
    }
669

670
    HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD_EX(
671
        constexpr, <=, bool, detail::enable_random_access_operations)
672
    {
673
        return 0 <=
674
            iterator_core_access::distance_to(static_cast<Derived1 const&>(lhs),
675
                static_cast<Derived2 const&>(rhs));
676
    }
677

678
    HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD_EX(
679
        constexpr, >=, bool, detail::enable_random_access_operations)
680
    {
681
        return 0 >=
22,520✔
682
            iterator_core_access::distance_to(static_cast<Derived1 const&>(lhs),
683
                static_cast<Derived2 const&>(rhs));
684
    }
685

686
    HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD_EX(constexpr, -,
687
        typename std::iterator_traits<Derived2>::difference_type,
15,020✔
688
        detail::enable_random_access_operations)
22,530✔
689
    {
690
        return iterator_core_access::distance_to(
691
            static_cast<Derived1 const&>(rhs),
692
            static_cast<Derived2 const&>(lhs));
693
    }
694

695
#undef HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD_EX
696
#undef HPX_UTIL_ITERATOR_FACADE_INTEROP_HEAD
697

698
    HPX_CXX_EXPORT template <typename Derived, typename T, typename Category,
699
        typename Reference, typename Distance, typename Pointer>
700
    HPX_HOST_DEVICE constexpr std::enable_if_t<
701
        std::is_same_v<typename Derived::iterator_category,
702
            std::random_access_iterator_tag>,
703
        Derived>
704
    operator+(iterator_facade<Derived, T, Category, Reference, Distance,
705
                  Pointer> const& it,
706
        typename Derived::difference_type
707
            n) noexcept(noexcept(std::declval<Derived>() +=
708
        std::declval<typename Derived::difference_type>()))
709
    {
710
        Derived tmp(static_cast<Derived const&>(it));
711
        return tmp += n;
712
    }
713

714
    HPX_CXX_EXPORT template <typename Derived, typename T, typename Category,
715
        typename Reference, typename Distance, typename Pointer>
716
    HPX_HOST_DEVICE constexpr std::enable_if_t<
717
        std::is_same_v<typename Derived::iterator_category,
718
            std::random_access_iterator_tag>,
719
        Derived>
720
    operator+(typename Derived::difference_type n,
721
        iterator_facade<Derived, T, Category, Reference, Distance,
722
            Pointer> const& it) noexcept(noexcept(std::declval<Derived>() +=
723
        std::declval<typename Derived::difference_type>()))
724
    {
725
        Derived tmp(static_cast<Derived const&>(it));
726
        return tmp += n;
727
    }
728
}    // namespace hpx::util
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc