Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/ranges/chunk by view"

From cppreference.com
< cpp‎ | ranges
m (Member functions: rm leading underscores "__")
m (Example: id+1/2/3/4.)
 
(21 intermediate revisions by 6 users not shown)
Line 7: Line 7:
 
           ranges::iterator_t<V>> Pred >
 
           ranges::iterator_t<V>> Pred >
 
     requires ranges::view<V> && std::is_object_v<Pred>
 
     requires ranges::view<V> && std::is_object_v<Pred>
class chunk_by_view : public ranges::view_interface<chunk_by_view<V, Pred>>
+
class chunk_by_view
 +
    : public ranges::view_interface<chunk_by_view<V, Pred>>
 
}}
 
}}
 
{{dcl|num=2|since=c++23|1=
 
{{dcl|num=2|since=c++23|1=
 
namespace views {
 
namespace views {
inline constexpr /* unspecified */ chunk_by = /* unspecified */ ;
+
    inline constexpr /* unspecified */ chunk_by = /* unspecified */ ;
 +
}
 
}}
 
}}
 
{{dcl h|Call signature}}
 
{{dcl h|Call signature}}
Line 21: Line 23:
 
{{dcl|since=c++23|1=
 
{{dcl|since=c++23|1=
 
template< class Pred >
 
template< class Pred >
constexpr __range_adaptor_closure chunk_by( Pred&& pred );
+
constexpr /*range adaptor closure*/ chunk_by( Pred&& pred );
 
}}
 
}}
{{dcl h|Helper templates}}
 
<!-- TODO: -->
 
 
{{dcl end}}
 
{{dcl end}}
  
@1@ {{tt|chunk_by_view}} is a range adaptor that takes a {{lconcept|view}} and an invocable object {{c|pred}} (the binary predicate), and produces a {{lconcept|view}} of subranges (chunks), by splitting the underlying view between each pair or adjacent elements for which predicate returns {{c|false}}. First element of each such pair belongs to the previous chunk, second element belongs to the next chunk.
+
@1@ {{tt|chunk_by_view}} is a range adaptor that takes a {{lconcept|view}} and an invocable object {{c|pred}} (the binary predicate), and produces a {{lconcept|view}} of subranges (chunks), by splitting the underlying view between each pair of adjacent elements for which {{c|pred}} returns {{c|false}}. The first element of each such pair belongs to the previous chunk, and the second element belongs to the next chunk.
  
@2@ The name {{c|views::chunk_by}} denotes a [[cpp/ranges#Range adaptor objects|ranges adaptor object]]. Given a subexpression {{c|e}} and {{c|f}}, the expression {{c|views::chunk_by(e, f)}} is ''expression-equivalent'' to {{c|chunk_by_view(e, f)}}.
+
@2@ The name {{c|views::chunk_by}} denotes a {{named req|RangeAdaptorObject}}. Given a subexpression {{c|e}} and {{c|f}}, the expression {{c|views::chunk_by(e, f)}} is [[cpp/language/expressions#Expression-equivalence|expression-equivalent]] to {{c|chunk_by_view(e, f)}}.
  
 
{{tt|chunk_by_view}} always models {{lconcept|forward_range}}, and models {{lconcept|bidirectional_range}} and/or {{lconcept|common_range}}, if adapted {{lconcept|view}} type models the corresponding concepts.
 
{{tt|chunk_by_view}} always models {{lconcept|forward_range}}, and models {{lconcept|bidirectional_range}} and/or {{lconcept|common_range}}, if adapted {{lconcept|view}} type models the corresponding concepts.
 
{{tt|chunk_by_view}} never models {{lconcept|borrowed_range}} or {{lconcept|sized_range}}.
 
{{tt|chunk_by_view}} never models {{lconcept|borrowed_range}} or {{lconcept|sized_range}}.
 
{{cpp/expr-eq}}
 
  
 
===Data members===
 
===Data members===
Typical implementations of {{tt|chunk_by_view}} hold three non-static data members:
+
{{dsc begin}}
* the underlying {{lconcept|view}} of type {{tt|V}} (shown here as {{tt|''base_''}} for exposition only),
+
{{dsc hitem|Member|Definition}}
* a wrapper that wraps the predicate used to split the elements of {{tt|''base_''}} of type {{c|__movable_box<Pred>}} (shown here as {{tt|''pred_''}} for exposition only), where {{ltt|cpp/ranges/copyable_wrapper|''__movable_box''}} is a wrapper class template that always satisfies {{lconcept|movable}}, <!-- P2325R3 --> <!-- "copyable" => "movable" -->
+
{{dsc expos mem obj|base_|id=base|spec={{tt|V}}|the underlying {{lconcept|view}}}}
* an object of {{lc|std::optional}}-like type (shown here as {{tt|''begin_''}} for exposition only) that caches an iterator to the first element.
+
{{dsc expos mem obj|pred_|id=pred|spec={{lti|cpp/ranges/copyable_wrapper|movable-box}}{{tti|<Pred>}}|an object that wraps the predicate used to split the elements of {{tti|base_}}}}
 +
{{dsc expos mem obj|begin_|id=begin|spec={{rlpi|non-propagating-cache|non-propagating-cache}}{{tti|<iterator>}}|an object that caches the iterator to the first element}}
 +
{{dsc end}}
  
 
===Member functions===
 
===Member functions===
Line 49: Line 49:
 
{{dsc inc|cpp/ranges/adaptor/dsc begin|chunk_by_view}}
 
{{dsc inc|cpp/ranges/adaptor/dsc begin|chunk_by_view}}
 
{{dsc inc|cpp/ranges/adaptor/dsc end|chunk_by_view}}
 
{{dsc inc|cpp/ranges/adaptor/dsc end|chunk_by_view}}
{{dsc expos mem fun|cpp/ranges/chunk_by_view/find_next|title=''find_next''|notes={{mark c++23}}|returns an iterator to the begin of the next subrange (the name is for exposition only)}}
+
{{dsc expos mem fun|cpp/ranges/chunk_by_view/helpers#find_next|title=''find_next''|returns an iterator to the begin of the next subrange}}
{{dsc expos mem fun|cpp/ranges/chunk_by_view/find_prev|title=''find_prev''|notes={{mark c++23}}|returns an iterator to the begin of the previous subrange (the name is for exposition only)}}
+
{{dsc expos mem fun|cpp/ranges/chunk_by_view/helpers#find_prev|title=''find_prev''|returns an iterator to the begin of the previous subrange}}
 
{{cpp/ranges/view_interface/inherit|embedded=yes|size=invalid|data=invalid|operator[]=invalid}}
 
{{cpp/ranges/view_interface/inherit|embedded=yes|size=invalid|data=invalid|operator[]=invalid}}
 
{{dsc end}}
 
{{dsc end}}
Line 58: Line 58:
 
===Nested classes===
 
===Nested classes===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc expos mem tclass|cpp/ranges/chunk_by_view/iterator|notes={{mark c++23}}|the iterator type}}
+
{{dsc expos mem tclass|cpp/ranges/chunk_by_view/iterator|the iterator type}}
 
{{dsc end}}
 
{{dsc end}}
  
 
===Notes===
 
===Notes===
In order to provide the amortized constant time complexity required by the {{lconcept|range}} concept, the result of {{rlt|begin}} is cached within the {{tt|chunk_by_view}} object. If the underlying range is modified after the first call to {{lc|begin()}}, subsequent uses of the {{tt|chunk_by_view}} object might have unintuitive behavior.
+
In order to provide the amortized constant time complexity required by the {{lconcept|range}} concept, the result of {{rltf|begin}} is cached within the {{tt|chunk_by_view}} object. If the underlying range is modified after the first call to {{rltf|begin}}, subsequent uses of the {{tt|chunk_by_view}} object might have unintuitive behavior.
  
 
{{feature test macro|__cpp_lib_ranges_chunk_by|std=C++23|value=202202L|{{tt|std::ranges::chunk_by_view}}}}
 
{{feature test macro|__cpp_lib_ranges_chunk_by|std=C++23|value=202202L|{{tt|std::ranges::chunk_by_view}}}}
Line 68: Line 68:
 
===Example===
 
===Example===
 
{{example
 
{{example
|A link to test: [https://godbolt.org/z/dcPGjx6MT Compiler Explorer]
 
 
|code=
 
|code=
 
#include <functional>
 
#include <functional>
Line 74: Line 73:
 
#include <ranges>
 
#include <ranges>
 
#include <string_view>
 
#include <string_view>
#include <vector>
 
  
void print_chunks(auto view, std::string_view separator = " ")
+
void print_chunks(auto view, std::string_view separator = ", ")
 
{
 
{
 
     for (auto const subrange : view)
 
     for (auto const subrange : view)
 
     {
 
     {
         std::cout << "[";
+
         std::cout << '[';
         for (std::string_view prefix = ""; auto const &elem : subrange)
+
         for (std::string_view prefix; auto const& elem : subrange)
        {
+
             std::cout << prefix << elem, prefix = separator;
             std::cout << prefix << elem;
+
            prefix = separator;
+
        }
+
 
         std::cout << "] ";
 
         std::cout << "] ";
 
     }
 
     }
Line 93: Line 88:
 
int main()
 
int main()
 
{
 
{
     {
+
     std::initializer_list v1 = {1, 2, 3, 1, 2, 3, 3, 3, 1, 2, 3};
        auto v = std::vector{1, 2, 3, 1, 2, 3, 3, 3, 1, 2, 3};
+
    auto fn1 = std::ranges::less{};
        auto fun = std::ranges::less{};
+
    auto view1 = v1 {{!}} std::views::chunk_by(fn1);
        auto view = v {{!}} std::views::chunk_by(fun);
+
    print_chunks(view1);
        print_chunks(view);
+
 
    }
+
     std::initializer_list v2 = {1, 2, 3, 4, 4, 0, 2, 3, 3, 3, 2, 1};
     {
+
    auto fn2 = std::ranges::not_equal_to{};
        auto v = std::vector{1, 2, 3, 4, 4, 0, 2, 3, 3, 3, 2, 1};
+
    auto view2 = v2 {{!}} std::views::chunk_by(fn2);
        auto fun = std::not_fn(std::ranges::equal_to{}); // or ranges::not_equal_to
+
    print_chunks(view2);
        auto view = v {{!}} std::views::chunk_by(fun);
+
 
        print_chunks(view);
+
     std::string_view v3 = "__cpp_lib_ranges_chunk_by";
    }
+
    auto fn3 = [](auto x, auto y) { return not(x == '_' or y == '_'); };
     {
+
    auto view3 = v3 {{!}} std::views::chunk_by(fn3);
        std::string v = "__cpp_lib_ranges_chunk_by";
+
    print_chunks(view3, "");
        auto fun = [](char x, char y) { return not(x == '_' or y == '_'); };
+
 
        auto view = v {{!}} std::views::chunk_by(fun);
+
     std::string_view v4 = "\u007a\u00df\u6c34\u{1f34c}"; // "zß水🍌"
        print_chunks(view, "");
+
    auto fn4 = [](auto, auto ß) { return 128 == ((128 + 64) & ß); };
     }
+
    auto view4 = v4 {{!}} std::views::chunk_by(fn4);
 +
    print_chunks(view4, "");
 
}
 
}
 
|output=
 
|output=
[1 2 3] [1 2 3] [3] [3] [1 2 3]
+
[1, 2, 3] [1, 2, 3] [3] [3] [1, 2, 3]  
[1 2 3 4] [4 0 2 3] [3] [3 2 1]
+
[1, 2, 3, 4] [4, 0, 2, 3] [3] [3, 2, 1]  
 
[_] [_] [cpp] [_] [lib] [_] [ranges] [_] [chunk] [_] [by]
 
[_] [_] [cpp] [_] [lib] [_] [ranges] [_] [chunk] [_] [by]
 +
[z] [ß] [水] [🍌]
 
}}
 
}}
  
 
===References===
 
===References===
 
{{ref std c++23}}
 
{{ref std c++23}}
{{ref std|title=Chunk by view|id=range.chunk.by|section=26.7.29}}
+
{{ref std|title=Chunk by view|id=range.chunk.by|section=26.7.30}}
 
{{ref std end}}
 
{{ref std end}}
  

Latest revision as of 13:03, 8 October 2024

 
 
Ranges library
Range adaptors
 
 
Defined in header <ranges>
template< ranges::forward_range V, std::indirect_binary_predicate<iterator_t<V>,

          ranges::iterator_t<V>> Pred >
    requires ranges::view<V> && std::is_object_v<Pred>
class chunk_by_view

    : public ranges::view_interface<chunk_by_view<V, Pred>>
(1) (since C++23)
namespace views {

    inline constexpr /* unspecified */ chunk_by = /* unspecified */ ;

}
(2) (since C++23)
Call signature
template< ranges::viewable_range R, class Pred >

    requires /* see below */

constexpr ranges::view auto chunk_by( R&& r, Pred&& pred );
(since C++23)
template< class Pred >
constexpr /*range adaptor closure*/ chunk_by( Pred&& pred );
(since C++23)
1) chunk_by_view is a range adaptor that takes a view and an invocable object pred (the binary predicate), and produces a view of subranges (chunks), by splitting the underlying view between each pair of adjacent elements for which pred returns false. The first element of each such pair belongs to the previous chunk, and the second element belongs to the next chunk.
2) The name views::chunk_by denotes a RangeAdaptorObject. Given a subexpression e and f, the expression views::chunk_by(e, f) is expression-equivalent to chunk_by_view(e, f).

chunk_by_view always models forward_range, and models bidirectional_range and/or common_range, if adapted view type models the corresponding concepts. chunk_by_view never models borrowed_range or sized_range.

Contents

[edit] Data members

Member Definition
V base_ the underlying view
(exposition-only member object*)
movable-box<Pred> pred_ an object that wraps the predicate used to split the elements of base_
(exposition-only member object*)
non-propagating-cache<iterator> begin_ an object that caches the iterator to the first element
(exposition-only member object*)

[edit] Member functions

constructs a chunk_by_view
(public member function) [edit]
returns a copy of the underlying (adapted) view
(public member function) [edit]
returns a reference to the stored predicate
(public member function) [edit]
returns an iterator to the beginning
(public member function) [edit]
returns an iterator or a sentinel to the end
(public member function) [edit]
returns an iterator to the begin of the next subrange
(exposition-only member function*)
returns an iterator to the begin of the previous subrange
(exposition-only member function*)
Inherited from std::ranges::view_interface
returns whether the derived view is empty. Provided if it satisfies sized_range or forward_range.
(public member function of std::ranges::view_interface<D>) [edit]
(C++23)
returns a constant iterator to the beginning of the range.
(public member function of std::ranges::view_interface<D>) [edit]
(C++23)
returns a sentinel for the constant iterator of the range.
(public member function of std::ranges::view_interface<D>) [edit]
returns whether the derived view is not empty. Provided if ranges::empty is applicable to it.
(public member function of std::ranges::view_interface<D>) [edit]
returns the first element in the derived view. Provided if it satisfies forward_range.
(public member function of std::ranges::view_interface<D>) [edit]
returns the last element in the derived view. Provided if it satisfies bidirectional_range and common_range.
(public member function of std::ranges::view_interface<D>) [edit]

[edit] Deduction guides

[edit] Nested classes

the iterator type
(exposition-only member class template*)

[edit] Notes

In order to provide the amortized constant time complexity required by the range concept, the result of begin() is cached within the chunk_by_view object. If the underlying range is modified after the first call to begin(), subsequent uses of the chunk_by_view object might have unintuitive behavior.

Feature-test macro Value Std Feature
__cpp_lib_ranges_chunk_by 202202L (C++23) std::ranges::chunk_by_view

[edit] Example

#include <functional>
#include <iostream>
#include <ranges>
#include <string_view>
 
void print_chunks(auto view, std::string_view separator = ", ")
{
    for (auto const subrange : view)
    {
        std::cout << '[';
        for (std::string_view prefix; auto const& elem : subrange)
            std::cout << prefix << elem, prefix = separator;
        std::cout << "] ";
    }
    std::cout << '\n';
}
 
int main()
{
    std::initializer_list v1 = {1, 2, 3, 1, 2, 3, 3, 3, 1, 2, 3};
    auto fn1 = std::ranges::less{};
    auto view1 = v1 | std::views::chunk_by(fn1);
    print_chunks(view1);
 
    std::initializer_list v2 = {1, 2, 3, 4, 4, 0, 2, 3, 3, 3, 2, 1};
    auto fn2 = std::ranges::not_equal_to{};
    auto view2 = v2 | std::views::chunk_by(fn2);
    print_chunks(view2);
 
    std::string_view v3 = "__cpp_lib_ranges_chunk_by";
    auto fn3 = [](auto x, auto y) { return not(x == '_' or y == '_'); };
    auto view3 = v3 | std::views::chunk_by(fn3);
    print_chunks(view3, "");
 
    std::string_view v4 = "\u007a\u00df\u6c34\u{1f34c}"; // "zß水🍌"
    auto fn4 = [](auto, auto ß) { return 128 == ((128 + 64) & ß); };
    auto view4 = v4 | std::views::chunk_by(fn4);
    print_chunks(view4, "");
}

Output:

[1, 2, 3] [1, 2, 3] [3] [3] [1, 2, 3] 
[1, 2, 3, 4] [4, 0, 2, 3] [3] [3, 2, 1] 
[_] [_] [cpp] [_] [lib] [_] [ranges] [_] [chunk] [_] [by]
[z] [ß] [水] [🍌]

[edit] References

  • C++23 standard (ISO/IEC 14882:2024):
  • 26.7.30 Chunk by view [range.chunk.by]

[edit] See also

a range of views that are N-sized non-overlapping successive chunks of the elements of another view
(class template) (range adaptor object)[edit]
a view whose Mth element is a view over the Mth through (M + N - 1)th elements of another view
(class template) (range adaptor object)[edit]
a view consisting of elements of another view, advancing over N elements at a time
(class template) (range adaptor object)[edit]