• 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

0.0
/libs/core/algorithms/include/hpx/parallel/algorithms/count.hpp
1
//  Copyright (c) 2022 Bhumit Attarde
2
//  Copyright (c) 2014 Grant Mercer
3
//  Copyright (c) 2020-2023 Hartmut Kaiser
4
//
5
//  SPDX-License-Identifier: BSL-1.0
6
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
7
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8

9
/// \file parallel/algorithms/count.hpp
10
/// \page hpx::count, hpx::count_if
11
/// \headerfile hpx/algorithm.hpp
12

13
#pragma once
14

15
#if defined(DOXYGEN)
16
namespace hpx {
17
    // clang-format off
18

19
    /// Returns the number of elements in the range [first, last) satisfying
20
    /// a specific criteria. This version counts the elements that are equal to
21
    /// the given \a value. Executed according to the policy.
22
    ///
23
    /// \note   Complexity: Performs exactly \a last - \a first comparisons.
24
    ///
25
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
26
    ///                     It describes the manner in which the execution
27
    ///                     of the algorithm may be parallelized and the manner
28
    ///                     in which it executes the comparisons.
29
    /// \tparam FwdIter    The type of the source iterator used (deduced).
30
    ///                     This iterator type must meet the requirements of an
31
    ///                     forward iterator.
32
    /// \tparam T           The type of the value to search for (deduced).
33
    ///
34
    /// \param policy       The execution policy to use for the scheduling of
35
    ///                     the iterations.
36
    /// \param first        Refers to the beginning of the sequence of elements
37
    ///                     the algorithm will be applied to.
38
    /// \param last         Refers to the end of the sequence of elements the
39
    ///                     algorithm will be applied to.
40
    /// \param value        The value to search for.
41
    ///
42
    /// The comparisons in the parallel \a count algorithm invoked with
43
    /// an execution policy object of type \a sequenced_policy
44
    /// execute in sequential order in the calling thread.
45
    ///
46
    /// \note The comparisons in the parallel \a count algorithm invoked with
47
    ///       an execution policy object of type \a parallel_policy or
48
    ///       \a parallel_task_policy are permitted to execute in an unordered
49
    ///       fashion in unspecified threads, and indeterminately sequenced
50
    ///       within each thread.
51
    ///
52
    /// \returns  The \a count algorithm returns a
53
    ///           \a hpx::future<difference_type> if the execution policy is of
54
    ///           type
55
    ///           \a sequenced_task_policy or
56
    ///           \a parallel_task_policy and
57
    ///           returns \a difference_type otherwise (where \a difference_type
58
    ///           is defined by \a std::iterator_traits<FwdIterB>::difference_type.
59
    ///           The \a count algorithm returns the number of elements
60
    ///           satisfying the given criteria.
61
    template <typename ExPolicy, typename FwdIter, typename T>
62
    typename util::detail::algorithm_result<ExPolicy,
63
        typename std::iterator_traits<FwdIter>::difference_type>::type
64
    count(ExPolicy&& policy, FwdIter first, FwdIter last, T const& value);
65

66
    /// Returns the number of elements in the range [first, last) satisfying
67
    /// a specific criteria. This version counts the elements that are equal to
68
    /// the given \a value.
69
    ///
70
    /// \note   Complexity: Performs exactly \a last - \a first comparisons.
71
    /// \tparam InIter      The type of the source iterator used (deduced).
72
    ///                     This iterator type must meet the requirements of an
73
    ///                     input iterator.
74
    /// \tparam T           The type of the value to search for (deduced).
75
    ///
76
    /// \param first        Refers to the beginning of the sequence of elements
77
    ///                     the algorithm will be applied to.
78
    /// \param last         Refers to the end of the sequence of elements the
79
    ///                     algorithm will be applied to.
80
    /// \param value        The value to search for.
81
    ///
82
    ///
83
    /// \returns  The \a count algorithm returns a \a difference_type (where \a difference_type
84
    ///           is defined by \a std::iterator_traits<InIter>::difference_type.
85
    ///           The \a count algorithm returns the number of elements
86
    ///           satisfying the given criteria.
87
    ///
88
    template <typename InIter, typename T>
89
    typename std::iterator_traits<InIter>::difference_type
90
    count(InIter first, InIter last, T const& value);
91

92
    /// Returns the number of elements in the range [first, last) satisfying
93
    /// a specific criteria. This version counts elements for which predicate
94
    /// \a f returns true. Executed according to the policy.
95
    ///
96
    /// \note   Complexity: Performs exactly \a last - \a first applications of
97
    ///         the predicate.
98
    ///
99
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
100
    ///                     It describes the manner in which the execution
101
    ///                     of the algorithm may be parallelized and the manner
102
    ///                     in which it executes the comparisons.
103
    /// \tparam FwdIter     The type of the source begin iterator used (deduced).
104
    ///                     This iterator type must meet the requirements of an
105
    ///                     forward iterator.
106
    /// \tparam F           The type of the function/function object to use
107
    ///                     (deduced). Unlike its sequential form, the parallel
108
    ///                     overload of \a count_if requires \a F to meet the
109
    ///                     requirements of \a CopyConstructible.
110
    ///
111
    /// \param policy       The execution policy to use for the scheduling of
112
    ///                     the iterations.
113
    /// \param first        Refers to the beginning of the sequence of elements
114
    ///                     the algorithm will be applied to.
115
    /// \param last         Refers to the end of the sequence of elements the
116
    ///                     algorithm will be applied to.
117
    /// \param f            Specifies the function (or function object) which
118
    ///                     will be invoked for each of the elements in the
119
    ///                     sequence specified by [first, last).This is an
120
    ///                     unary predicate which returns \a true for the
121
    ///                     required elements. The signature of this predicate
122
    ///                     should be equivalent to:
123
    ///                     \code
124
    ///                     bool pred(const Type &a);
125
    ///                     \endcode \n
126
    ///                     The signature does not need to have const&, but
127
    ///                     the function must not modify the objects passed to
128
    ///                     it. The type \a Type must be such that an object of
129
    ///                     type \a FwdIter can be dereferenced and then
130
    ///                     implicitly converted to Type.
131
    ///
132
    /// \note The assignments in the parallel \a count_if algorithm invoked with
133
    ///       an execution policy object of type \a sequenced_policy
134
    ///       execute in sequential order in the calling thread.
135
    /// \note The assignments in the parallel \a count_if algorithm invoked with
136
    ///       an execution policy object of type \a parallel_policy or
137
    ///       \a parallel_task_policy are permitted to execute in an unordered
138
    ///       fashion in unspecified threads, and indeterminately sequenced
139
    ///       within each thread.
140
    ///
141
    /// \returns  The \a count_if algorithm returns
142
    ///           \a hpx::future<difference_type> if the execution policy is of
143
    ///           type
144
    ///           \a sequenced_task_policy or
145
    ///           \a parallel_task_policy and
146
    ///           returns \a difference_type otherwise (where \a difference_type
147
    ///           is defined by \a std::iterator_traits<FwdIter>::difference_type.
148
    ///           The \a count algorithm returns the number of elements
149
    ///           satisfying the given criteria.
150
    ///
151
    template <typename ExPolicy, typename FwdIter, typename F>
152
    typename util::detail::algorithm_result<ExPolicy,
153
        typename std::iterator_traits<FwdIter>::difference_type>::type
154
    count_if(ExPolicy&& policy, FwdIter first, FwdIter last, F&& f);
155

156
    /// Returns the number of elements in the range [first, last) satisfying
157
    /// a specific criteria. This version counts elements for which predicate
158
    /// \a f returns true.
159
    ///
160
    /// \note   Complexity: Performs exactly \a last - \a first applications of
161
    ///         the predicate.
162
    ///
163
    /// \tparam InIter      The type of the source begin iterator used (deduced).
164
    ///                     This iterator type must meet the requirements of an
165
    ///                     input iterator.
166
    /// \tparam F           The type of the function/function object to use
167
    ///                     (deduced). Unlike its sequential form, the parallel
168
    ///                     overload of \a count_if requires \a F to meet the
169
    ///                     requirements of \a CopyConstructible.
170
    ///
171
    /// \param first        Refers to the beginning of the sequence of elements
172
    ///                     the algorithm will be applied to.
173
    /// \param last         Refers to the end of the sequence of elements the
174
    ///                     algorithm will be applied to.
175
    /// \param f            Specifies the function (or function object) which
176
    ///                     will be invoked for each of the elements in the
177
    ///                     sequence specified by [first, last).This is an
178
    ///                     unary predicate which returns \a true for the
179
    ///                     required elements. The signature of this predicate
180
    ///                     should be equivalent to:
181
    ///                     \code
182
    ///                     bool pred(const Type &a);
183
    ///                     \endcode \n
184
    ///                     The signature does not need to have const&, but
185
    ///                     the function must not modify the objects passed to
186
    ///                     it. The type \a Type must be such that an object of
187
    ///                     type \a InIter can be dereferenced and then
188
    ///                     implicitly converted to Type.
189
    ///
190
    /// \returns  The \a count_if algorithm returns \a difference_type (where
191
    ///           a difference_type is defined by
192
    ///           \a std::iterator_traits<InIter>::difference_type.
193
    ///           The \a count algorithm returns the number of elements
194
    ///           satisfying the given criteria.
195
    ///
196
    template <typename InIter, typename F>
197
        typename std::iterator_traits<InIter>::difference_type
198
    count_if(InIter first, InIter last, F&& f);
199

200
    // clang-format on
201
}    // namespace hpx
202

203
#else    // DOXYGEN
204

205
#include <hpx/config.hpp>
206
#include <hpx/modules/concepts.hpp>
207
#include <hpx/modules/execution.hpp>
208
#include <hpx/modules/executors.hpp>
209
#include <hpx/modules/functional.hpp>
210
#include <hpx/modules/iterator_support.hpp>
211
#include <hpx/modules/pack_traversal.hpp>
212
#include <hpx/modules/type_support.hpp>
213
#include <hpx/parallel/algorithms/detail/dispatch.hpp>
214
#include <hpx/parallel/algorithms/detail/distance.hpp>
215
#include <hpx/parallel/util/detail/algorithm_result.hpp>
216
#include <hpx/parallel/util/detail/sender_util.hpp>
217
#include <hpx/parallel/util/loop.hpp>
218
#include <hpx/parallel/util/partitioner.hpp>
219

220
#include <algorithm>
221
#include <cstddef>
222
#include <functional>
223
#include <iterator>
224
#include <type_traits>
225
#include <utility>
226

227
namespace hpx::parallel {
228

229
    ///////////////////////////////////////////////////////////////////////////
230
    // count
231
    namespace detail {
232

233
        /// \cond NOINTERNAL
234
        HPX_CXX_EXPORT template <typename ExPolicy, typename Op, typename Proj>
235
        struct count_iteration
236
        {
237
            using execution_policy_type = std::decay_t<ExPolicy>;
238
            using proj_type = std::decay_t<Proj>;
239
            using op_type = std::decay_t<Op>;
240

241
            op_type op_;
242
            proj_type proj_;
243

244
            template <typename Op_, typename Proj_,
245
                typename U = std::enable_if_t<
246
                    !std::is_same_v<std::decay_t<Op_>, count_iteration>>>
247
            HPX_HOST_DEVICE count_iteration(Op_&& op, Proj_&& proj)
248
              : op_(HPX_FORWARD(Op_, op))
249
              , proj_(HPX_FORWARD(Proj_, proj))
×
250
            {
251
            }
252

253
#if !defined(__NVCC__) && !defined(__CUDACC__)
254
            count_iteration(count_iteration const&) = default;
255
            count_iteration(count_iteration&&) = default;
256
#else
257
            HPX_HOST_DEVICE count_iteration(count_iteration const& rhs)
258
              : op_(rhs.op_)
259
              , proj_(rhs.proj_)
260
            {
261
            }
262

263
            HPX_HOST_DEVICE count_iteration(count_iteration&& rhs)
264
              : op_(HPX_MOVE(rhs.op_))
265
              , proj_(HPX_MOVE(rhs.proj_))
266
            {
267
            }
268
#endif
269

270
            count_iteration& operator=(count_iteration const&) = default;
271
            count_iteration& operator=(count_iteration&&) = default;
272

273
            template <typename Iter>
274
            HPX_HOST_DEVICE HPX_FORCEINLINE constexpr
275
                typename std::iterator_traits<Iter>::difference_type
276
                operator()(Iter part_begin, std::size_t part_size)
277
            {
278
                typename std::iterator_traits<Iter>::difference_type ret = 0;
279
                util::loop_n<execution_policy_type>(part_begin, part_size,
280
                    hpx::bind_back(*this, std::ref(ret)));
281
                return ret;
282
            }
283

284
            template <typename Iter>
285
            HPX_HOST_DEVICE HPX_FORCEINLINE constexpr void operator()(Iter curr,
286
                typename std::iterator_traits<Iter>::difference_type& ret)
287
            {
288
                ret += traits::count_bits(
×
289
                    HPX_INVOKE(op_, HPX_INVOKE(proj_, *curr)));
×
290
            }
291
        };
292

293
        ///////////////////////////////////////////////////////////////////////
294
        HPX_CXX_EXPORT template <typename Value>
295
        struct count : public algorithm<count<Value>, Value>
296
        {
297
            typedef Value difference_type;
298

299
            constexpr count() noexcept
300
              : algorithm<count, Value>("count")
301
            {
302
            }
303

304
            template <typename ExPolicy, typename InIterB, typename InIterE,
305
                typename T, typename Proj>
306
            static difference_type sequential(ExPolicy&& policy, InIterB first,
×
307
                InIterE last, T const& value, Proj&& proj)
308
            {
309
                auto f1 =
310
                    count_iteration<ExPolicy, detail::compare_to<T>, Proj>(
311
                        detail::compare_to<T>(value), HPX_FORWARD(Proj, proj));
312

313
                typename std::iterator_traits<InIterB>::difference_type ret = 0;
×
314

315
                util::loop(HPX_FORWARD(ExPolicy, policy), first, last,
316
                    hpx::bind_back(HPX_MOVE(f1), std::ref(ret)));
×
317

318
                return ret;
×
319
            }
320

321
            template <typename ExPolicy, typename IterB, typename IterE,
322
                typename T, typename Proj>
323
            static decltype(auto) parallel(ExPolicy&& policy, IterB first,
324
                IterE last, T const& value, Proj&& proj)
325
            {
326
                constexpr bool has_scheduler_executor =
327
                    hpx::execution_policy_has_scheduler_executor_v<ExPolicy>;
328

329
                if constexpr (!has_scheduler_executor)
330
                {
331
                    if (first == last)
332
                    {
333
                        return util::detail::
334
                            algorithm_result<ExPolicy, difference_type>::get(
335
                                static_cast<difference_type>(0));
336
                    }
337
                }
338

339
                auto f1 =
340
                    count_iteration<ExPolicy, detail::compare_to<T>, Proj>(
341
                        detail::compare_to<T>(value), HPX_FORWARD(Proj, proj));
342

343
                return util::partitioner<ExPolicy, difference_type>::call(
344
                    HPX_FORWARD(ExPolicy, policy), first,
345
                    detail::distance(first, last), HPX_MOVE(f1),
346
                    hpx::unwrapping([](auto&& results, auto&&...) {
347
                        return util::accumulate_n(hpx::util::begin(results),
348
                            hpx::util::size(results), difference_type(0),
349
                            std::plus<difference_type>());
350
                    }));
351
            }
352
        };
353
        /// \endcond
354
    }    // namespace detail
355

356
    ///////////////////////////////////////////////////////////////////////////
357
    // count_if
358
    namespace detail {
359

360
        /// \cond NOINTERNAL
361
        HPX_CXX_EXPORT template <typename Value>
362
        struct count_if : public algorithm<count_if<Value>, Value>
363
        {
364
            using difference_type = Value;
365

366
            constexpr count_if() noexcept
367
              : algorithm<count_if, Value>("count_if")
368
            {
369
            }
370

371
            template <typename ExPolicy, typename InIterB, typename InIterE,
372
                typename Pred, typename Proj>
373
            static constexpr difference_type sequential(ExPolicy&& policy,
374
                InIterB first, InIterE last, Pred&& op, Proj&& proj)
375
            {
376
                auto f1 = count_iteration<ExPolicy, Pred, Proj>(
377
                    op, HPX_FORWARD(Proj, proj));
378

379
                typename std::iterator_traits<InIterB>::difference_type ret = 0;
380

381
                util::loop(HPX_FORWARD(ExPolicy, policy), first, last,
382
                    hpx::bind_back(HPX_MOVE(f1), std::ref(ret)));
383

384
                return ret;
385
            }
386

387
            template <typename ExPolicy, typename IterB, typename IterE,
388
                typename Pred, typename Proj>
389
            static decltype(auto) parallel(ExPolicy&& policy, IterB first,
390
                IterE last, Pred&& op, Proj&& proj)
391
            {
392
                constexpr bool has_scheduler_executor =
393
                    hpx::execution_policy_has_scheduler_executor_v<ExPolicy>;
394

395
                if constexpr (!has_scheduler_executor)
396
                {
397
                    if (first == last)
398
                    {
399
                        return util::detail::
400
                            algorithm_result<ExPolicy, difference_type>::get(
401
                                static_cast<difference_type>(0));
402
                    }
403
                }
404

405
                auto f1 = count_iteration<ExPolicy, Pred, Proj>(
406
                    op, HPX_FORWARD(Proj, proj));
407

408
                return util::partitioner<ExPolicy, difference_type>::call(
409
                    HPX_FORWARD(ExPolicy, policy), first,
410
                    detail::distance(first, last), HPX_MOVE(f1),
411
                    hpx::unwrapping([](auto&& results, auto&&...) {
412
                        return util::accumulate_n(hpx::util::begin(results),
413
                            hpx::util::size(results), difference_type(0),
414
                            std::plus<difference_type>());
415
                    }));
416
            }
417
        };
418
        /// \endcond
419
    }    // namespace detail
420
}    // namespace hpx::parallel
421

422
namespace hpx {
423

424
    ///////////////////////////////////////////////////////////////////////////
425
    // CPO for hpx::count
426
    HPX_CXX_EXPORT inline constexpr struct count_t final
427
      : hpx::detail::tag_parallel_algorithm<count_t>
428
    {
429
    private:
430
        template <typename ExPolicy, typename FwdIter,
431
            typename T = typename std::iterator_traits<FwdIter>::value_type>
432
        // clang-format off
433
            requires (
434
                hpx::is_execution_policy_v<ExPolicy> &&
435
                hpx::traits::is_iterator_v<FwdIter>
436
            )
437
        // clang-format on
438
        friend decltype(auto) tag_fallback_invoke(count_t, ExPolicy&& policy,
439
            FwdIter first, FwdIter last, T const& value)
440
        {
441
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
442
                "Required at least forward iterator.");
443

444
            using difference_type =
445
                typename std::iterator_traits<FwdIter>::difference_type;
446

447
            return hpx::parallel::detail::count<difference_type>().call(
448
                HPX_FORWARD(ExPolicy, policy), first, last, value,
449
                hpx::identity_v);
450
        }
451

452
        template <typename InIter,
453
            typename T = typename std::iterator_traits<InIter>::value_type>
454
        // clang-format off
455
            requires (
456
                hpx::traits::is_iterator_v<InIter>
457
            )
458
        // clang-format on
459
        friend typename std::iterator_traits<InIter>::difference_type
460
        tag_fallback_invoke(count_t, InIter first, InIter last, T const& value)
461
        {
462
            static_assert(hpx::traits::is_input_iterator_v<InIter>,
463
                "Required at least input iterator.");
464

465
            using difference_type =
466
                typename std::iterator_traits<InIter>::difference_type;
467

468
            return hpx::parallel::detail::count<difference_type>().call(
469
                hpx::execution::seq, first, last, value, hpx::identity_v);
470
        }
471
    } count{};
472

473
    ///////////////////////////////////////////////////////////////////////////
474
    // CPO for hpx::count_if
475
    HPX_CXX_EXPORT inline constexpr struct count_if_t final
476
      : hpx::detail::tag_parallel_algorithm<count_if_t>
477
    {
478
    private:
479
        template <typename ExPolicy, typename FwdIter, typename F>
480
        // clang-format off
481
        requires (
482
                hpx::is_execution_policy_v<ExPolicy> &&
483
                hpx::traits::is_iterator_v<FwdIter> &&
484
                hpx::is_invocable_v<F,
485
                    typename std::iterator_traits<FwdIter>::value_type
486
                >
487
            )
488
        // clang-format on
489
        friend decltype(auto) tag_fallback_invoke(
490
            count_if_t, ExPolicy&& policy, FwdIter first, FwdIter last, F f)
491
        {
492
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
493
                "Required at least forward iterator.");
494

495
            using difference_type =
496
                typename std::iterator_traits<FwdIter>::difference_type;
497

498
            return hpx::parallel::detail::count_if<difference_type>().call(
499
                HPX_FORWARD(ExPolicy, policy), first, last, HPX_MOVE(f),
500
                hpx::identity_v);
501
        }
502

503
        template <typename InIter, typename F>
504
        // clang-format off
505
            requires (
506
                hpx::traits::is_iterator_v<InIter> &&
507
                hpx::is_invocable_v<F,
508
                    typename std::iterator_traits<InIter>::value_type
509
                >
510
            )
511
        // clang-format on
512
        friend typename std::iterator_traits<InIter>::difference_type
513
        tag_fallback_invoke(count_if_t, InIter first, InIter last, F f)
514
        {
515
            static_assert(hpx::traits::is_input_iterator_v<InIter>,
516
                "Required at least input iterator.");
517

518
            using difference_type =
519
                typename std::iterator_traits<InIter>::difference_type;
520

521
            return hpx::parallel::detail::count_if<difference_type>().call(
522
                hpx::execution::seq, first, last, HPX_MOVE(f), hpx::identity_v);
523
        }
524
    } count_if{};
525
}    // namespace hpx
526

527
#endif    // DOXYGEN
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

© 2026 Coveralls, Inc