<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title><code>views::take_before
  </code></title>
  <style type="text/css">
    body {
      font-variant-ligatures: none;
    }

    p {
      text-align: justify
    }

    li {
      text-align: justify
    }

    blockquote.note,
    div.note {
      background-color: #E0E0E0;
      padding-left: 15px;
      padding-right: 15px;
      padding-top: 1px;
      padding-bottom: 1px;
    }

    p code {
      color: navy
    }

    ins p code {
      color: #00A000
    }

    p ins code {
      color: #00A000
    }

    p del code {
      color: #A00000
    }

    ins {
      color: #00A000
    }

    del {
      color: #A00000
    }

    table#boilerplate {
      border: 0
    }

    table#boilerplate td {
      padding-left: 2em
    }

    table.bordered,
    table.bordered th,
    table.bordered td {
      border: 1px solid;
      text-align: center;
    }

    ins.block {
      color: #00A000;
      text-decoration: none
    }

    del.block {
      color: #A00000;
      text-decoration: none
    }

    #hidedel:checked~* del,
    #hidedel:checked~* del * {
      display: none;
      visibility: hidden
    }
  </style>
</head>

<body data-new-gr-c-s-check-loaded="14.1043.0" data-gr-ext-installed="">
  <table id="boilerplate">
    <tbody>
      <tr>
        <td>Document number</td>
        <td>P3220R1</td>
      </tr>
      <tr>
        <td>Date</td>
        <td>2025-06-16</td>
      </tr>
      <tr>
        <td>Audience</td>
        <td>LEWG, SG9 (Ranges)</td>
      </tr>
      <tr>
        <td>Reply-to</td>
        <td>Hewill Kang &lt;hewillk@gmail.com&gt;</td>
      </tr>
    </tbody>
  </table>
  <hr>
  <h1><code>views::take_before</code></h1>
  <ul>
    <li>
      <ul>
        <li>Abstract</li>
        <li>Revision history</li>
        <li>Discussion</li>
        <li>Design</li>
        <li>Implementation experience</li>
        <li>Proposed change</li>
        <li>References</li>
      </ul>
    </li>
  </ul>
  <a name="Abstract"></a>
  <h2>Abstract</h2>
  <p>
    This paper proposes the Tier 1 adaptor in <a
      href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2760r1.html">P2760</a>:
    <code>views::delimit</code>, which is renamed into <code>views::take_before</code> along with its corresponding view
    class to improve the C++29
    ranges facilities.
  </p>
  <a name="Revision history"></a>
  <h2>Revision history</h2>
  <p>
  <h3>R0</h3>
  <p>Initial revision.</p>
  <h3>R1</h3>
  <p>Rename <code>views::delimit</code> to <code>views::take_before</code> based on feedback from Sofia SG9.</p>
  <p>Extend conditional borrowed ranges for
    <code>views::take_before(p, '\0')</code>.
  </p>
  </ol>
  </p>
  <a name="Discussion"></a>
  <h2>Discussion</h2>
  <p>
    <code>views::take_before</code> accepts a range (or iterator) and a specified value and produces a range ending with
    the
    first
    occurrence of that
    value. One common usage is to construct a NTBS range without calculating its actual length, for example:
  </p>
  <pre>
  const char* p = /* from elsewhere */;
  const auto ntbs = views::take_before(p, '\0');</pre>
  <p>
    In other words, it is somewhat similar to the value-comparison version of <code>views::take_while</code>, which was
    originally classified into the <code>take</code>/<code>drop</code> family
    in <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2214r2.html">P2214</a>.
    Following the schedule of C++23 high-priority adaptors, <code>views::take_before</code> has now been moved from
    Tier 2 to Tier 1, as it provides an intuitive way to treat an element with a specific value as a sentinel.</p>
  </p>
  </ol>
  <a name="Design"></a>
  <h2>Design</h2>
  <p>
  <h3>
    Why not just <code>r | views::take_while(...)</code>?</h3>
  <p><code>r | views::take_before(v)</code> is basically equivalent to
    <code>r | views::take_while([v](const auto& e) { return e != v; })</code>,
    which seems that it is sufficient to just implement it via <code>views::take_while</code>.
    However, doing so is not an appropriate choice for the following reasons.
  </p>
  <p>
    First, it's unclear whether to save <code>v</code> in a lambda or use
    <code>bind_front(ranges::not_equal_to, v)</code> for a more general purpose,
    which introduces extra indirection anyway. In other words, if we only want to
    compare <code>*it == v</code>, it will be done indirectly by
    <code>invoke(bind_front(ranges::not_equal_to, v), *it)</code> -&gt; <code>ranges::not_equal_to(v , *it)</code>
    -&gt; <code>*it == v</code> in case of using <code>views::take_while</code>. As a result, we inevitably pay the
    cost of two extra function calls,
    which may bring performance issues because it is unrealistic to assume that the compiler can optimize out these
    calls
    in <i>any</i> case.
  </p>
  </p>
  <p>Secondly, additional specific constraints need to be introduced. Take
    lambda as an example,
    we should ensure that
    <code>[v = forward&lt;V&gt;(v)](const auto& e) -> bool { return e != v; }</code> can be constructed, but we
    cannot just put it in the <code>requires</code>-clause because capture list can produce hard
    errors, and the return statement also requires corresponding constraint.
    This indicates that at least <code>constructible_from&lt;decay_t&lt;V&gt;, V&gt;</code> and
    <code>equality_comparable_with&lt;range_reference_t&lt;R&gt, V&gt;</code> need to be added to the adaptor's call
    operator, such a lengthy constraint seems bloated and ugly.
    Note that this is also true when using <code>bind_front</code>, as it is not a constraint function either.
  </p>
  <p>
    Instead, if a new <code>take_before_view</code> class is introduced, we can just check whether
    <code>take_before_view(E, F)</code> is
    well-formed because the class already has the correct constraints.
  </p>
  <p>Finally, if the bottom layer of <code>views::take_before</code> is <code>take_while_view</code>,
    then the former will have a <code>pred()</code> member which returns the <i>internal</i> lambda.
    This can lead to untold confusion, as the user passes in a value, but all he gets back is an unspecified predicate,
    and there's really not much use in getting such an unspecified object.
  </p>
  <p>
    To sum up, it is necessary to introduce a new <code>take_before_view</code> class which is not that complicated.</p>
  <h3>What are the constraints for <code>take_before_view</code>?</h3>
  <p>The implementation of <code>take_before_view</code> is very similar to <code>take_while_view</code>.
    The difference is that we need to save a value instead of a predicate, and its sentinel needs to compare the current
    element with the value instead of invoking the predicate.</p>
  <p>First, the value type needs to model <code>move_constructible</code> to be wrapped by
    <code><i>movable-box</i></code>:
  </p>
  <pre>
    template&lt;view V, move_constructible T&gt;
      requires input_range&lt;V&gt; &amp;&amp; is_object_v&lt;T&gt; &amp;&amp; /* */
    class take_before_view : public view_interface&lt;take_before_view&lt;V, T&gt;&gt; {
      [&hellip;]
    };</pre>
  We also need to require the <code>*it == v</code> is well-formed. In range/v3 this
  part is spelled as
  <code>equality_comparable_with&lt;V, range_reference_t&lt;R&gt;&gt;</code> which is straightforward.</p>
  <p>However, the author prefers to use
    <code>indirect_binary_predicate&lt;ranges::equal_to, iterator_t&lt;V&gt;, const T*&gt;</code>
    to further comply with the mathematical sound for cross-type equality comparison,
    even if this require that <code>range_value_t&lt;R&gt;</code> needs to be comparable with <code>V</code> which does
    not involve in the implementation.
  <p>This makes the constraints of <code>take_before_view</code> corresponding to <code>take_while_view</code>
    consistent with <code>ranges::find</code> corresponding to <code>ranges::find_if</code>.</p>
  <h3>Should we provide in-place constructors for <code>take_before_view</code>?</h3>
  <p>Nope.</p>
  <p>
    <code>take_before_view</code> takes ownership of the value which might be more efficient to construct it via
    in-place
    construction, so it seems reasonable to provide such a constructor like
    <code>take_before_view(V base, in_place_t, Args&amp;&amp;... args)</code>.
  </p>
  However, unlike <code>single_view</code>/<code>repeat_view</code>, in this case, we also need to explicitly specify
  the type of <code>V</code> for <code>take_before_view</code>, which was actually deduced by CTAD before.
  It turns out that introducing such a constructor does not have much usability.
  </p>
  <h3>Should we support the iterator version of <code>views::take_before</code>?</h3>
  <p>range/v3's <code>views::take_before</code> also supports accepting an iterator <code>it</code> that returns <code>subrange(it, unreachable_sentinel)
    | views::take_before(v)</code>. Providing such overloading does have a certain value, because sometimes we may only
    have
    <code>const char*</code>.
  </p>
  <h3>Do we need to introduce <code>views::c_str</code> as well?</h3>
  <p>
    <code>views::c_str</code> is also classified in T1 in <a
      href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2760r1.html">P2760</a>,
    which allows us to view a null-terminated character array as a range. It produces a sized
    <code>subrange&lt;const char*, const char*&gt;</code> when taking <code>const char (&)[N]</code> such as string
    literals,
    and <code>views::take_before(p, '\0')</code> when taking a character pointer <code>p</code>.
  </p>
  <p>Since the former can be easily achieved through <code>views::all("hello")</code> or <code>subrange("hello")</code>,
    and the latter is just another way of writing <code>views::take_before('\0')</code>, the author believes that the
    value
    it provides is limited, so it is not introduced in this paper. However, the author remains neutral.</p>
  <h3><code>views::take_before</code> vs <code>views::take_until</code>?</h3>
  At the Sofia meeting, SG9 agreed that <code>take_before</code> is a more appropriate name for this adaptor, as the
  semantics of
  <i>before</i> are clear and intuitively indicate that the resulting range ends prior to the specified value. While an
  alternative name such as <code>take_until</code> was considered, it introduces potential ambiguity regarding whether
  the
  terminating value is included or excluded. Such ambiguity is undesirable, particularly in the context of C++ Ranges,
  which places a strong emphasis on clarity, consistency, and semantic predictability in naming. The author concurs with
  this assessment and prefers the name <code>take_before</code>.
  <h3>Should <code>views::take_before(p, '\0')</code> be a borrowed range?</h3>
  <p>In R0, the specified value is always stored in <code>take_before_view</code> with its sentinel storing a pointer to
    <code>take_before_view</code> for accessing the value, which makes <code>take_before_view</code> never a borrowed
    range.
  </p>
  <p>During Sofia meeting, SG9 raised concerns that this might not be desirable since such non-borrowability would inconvenience
    users.</p>
  <p> For trivial values such as integers, we can store them in the sentinel so that
    <code>views::take_before(p, '\0')</code> or <code>views::take_before(r, 42)</code> can be a borrowed range,
    which also eliminates indirect access to the value when checking for end.
  </p>
  <p>
    The author adopts such optimization for all scalar types to
    accommodate the most common real-world use cases:

  <pre>
  const char* p = "Hello, World!";
  auto r0 = views::take_before(p, '\0');               // borrowed range

  auto ints = {1, 2, 42, 3, 4, 5};
  auto r1 = views::take_before(ints, 42);              // borrowed range

  auto r2 = views::iota(9) | views::take_before(17);   // borrowed range

  vector&lt;string&gt; strs{"1", "2", "42", "3", "4", "5"};
  auto r3 = strs | views::take_before("42");            // borrowed range
  auto r4 = strs | views::take_before("42"s);           // non-borrowed range
  auto r5 = strs | views::take_before("42"sv);          // non-borrowed range
</pre>
  <a name="Implementation experience"></a>
  <h2>Implementation experience</h2>
  <p>The author implemented <code>views::take_before</code> based on libc++,
    see <a href="https://godbolt.org/z/9xeWMWzo7">here</a>.</p>

  <a name="Proposed-change"></a>
  <h2>Proposed change</h2>
  <p>This wording is relative to <a href="https://eel.is/c++draft">latest working draft</a>.
  </p>
  </div>
  <div>
    <ol>
      <ol>
        <li>
          <p>Add a new feature-test macro to 17.3.2 <a href="https://eel.is/c++draft/version.syn">[version.syn]</a>:
          </p>
          <blockquote>
            <pre><ins>#define __cpp_lib_ranges_take_before 2025XXL // <i>freestanding, also in</i> &lt;ranges&gt;</ins></pre>
          </blockquote>
        </li>

        <li>
          <p>Modify 25.2 <a href="https://eel.is/c++draft/ranges.syn">[ranges.syn]</a>, Header <tt>&lt;ranges&gt;</tt>
            synopsis, as indicated:</p>

          <blockquote>
            <pre>
#include &lt;compare&gt;              // <i>see <a href="https://eel.is/c++draft/compare.syn">[compare.syn]</a></i>
#include &lt;initializer_list&gt;     // <i>see <a href="https://eel.is/c++draft/initializer.list.syn">[initializer.list.syn]</a></i>
#include &lt;iterator&gt;             // <i>see <a href="https://eel.is/c++draft/iterator.synopsis">[iterator.synopsis]</a></i>

namespace std::ranges {
  [&hellip;]
  namespace views { inline constexpr <i>unspecified</i> drop_while = <i>unspecified</i>; }

<ins>  // <i>[range.take.before]</a>, take before view</i>
  template&lt;view V, move_constructible T&gt;
    requires input_range&lt;V&gt; &amp;&amp; is_object_v&lt;T&gt; &amp;&amp;
             indirect_binary_predicate&lt;ranges::equal_to, iterator_t&lt;V&gt;, const T*&gt;
    class take_before_view;

  template&lt;class V, class T&gt;
    constexpr bool enable_borrowed_range&lt;take_before_view&lt;V, T&gt;&gt; = is_scalar_v&lt;T&gt;;

  namespace views { inline constexpr <i>unspecified</i> take_before = <i>unspecified</i>; }</ins>
  [&hellip;]
}
        </pre>
          </blockquote>
        </li>
        <li>
          <p>Add <b>26.7.? Take before view [range.take.before]</b></a> after 26.7.13 <a
              href="https://eel.is/c++draft/range.drop.while">[range.drop.while]</a> as indicated:</p>
          <p>[26.7.?.1] Overview [range.take.before.overview]</p>
          <p>
            -1- Given a specified value <code>val</code> and a view <code>r</code>, <code>take_before_view</code>
            produces
            a
            view of the range [<code>ranges::begin(r), ranges::find(r, val)</code>).</p>
          </p>
          <p>-2-
            The name <code>views::take_before</code> denotes a range adaptor object (<a
              href="https://eel.is/c++draft/range.adaptor.object">[range.adaptor.object]</a>).

            Let <code>E</code> and <code>F</code> be expressions, and let <code>T</code> be
            <code>remove_cvref_t&lt;decltype((E))&gt;</code>.
            The expression <code>views::take_before(E, F)</code> is expression-equivalent to
            <code>take_before_view(subrange(E, unreachable_sentinel), F)</code> if <code>T</code> models
            <code>input_iterator</code> and dose not model <code>range</code>; otherwise,
            <code>take_before_view(E, F)</code>.
          </p>
          <p>-3- [<i>Example 1</i>:</p>
          <pre>
  const char* one_two = "One?Two";
  for (auto c : views::take_before(one_two, '?')) {
    cout &lt;&lt; c;                 // <i>prints</i> One
  }</pre>
          — <i>end example]</i>
          <p>[26.7.?.2] Class template <code>take_before_view</code> [range.take.before.view]</p>
          <pre>
  namespace std::ranges {
    template&lt;view V, move_constructible T&gt;
      requires input_range&lt;V&gt; &amp;&amp; is_object_v&lt;T&gt; &amp;&amp;
               indirect_binary_predicate&lt;ranges::equal_to, iterator_t&lt;V&gt;, const T*&gt;
    class take_before_view : public view_interface&lt;take_before_view&lt;V, T&gt;&gt; {
      // <i>[range.take.before.sentinel], class template</i> take_before_view::<i>sentinel</i>
      template&lt;bool&gt; class <i>sentinel</i>;                             // <i>exposition only</i>
  
      V <i>base_</i> = V();                                             // <i>exposition only</i>
      <i>movable-box</i>&lt;T&gt; <i>value_</i>;                                     // <i>exposition only</i>
  
    public:
      take_before_view() requires default_initializable&lt;V&gt; &amp;&amp; default_initializable&lt;T&gt; = default;
      constexpr explicit take_before_view(V base, const T& value) requires copy_constructible&lt;T&gt;;
      constexpr explicit take_before_view(V base, T&& value);
  
      constexpr V base() const & requires copy_constructible&lt;V&gt; { return <i>base_</i>; }
      constexpr V base() &amp;&amp; { return std::move(<i>base_</i>); }
  
      constexpr auto begin() requires (!<i>simple-view</i>&lt;V&gt;)
      { return ranges::begin(<i>base_</i>); }
  
      constexpr auto begin() const
        requires range&lt;const V&gt; &amp;&amp;
                 indirect_binary_predicate&lt;ranges::equal_to, iterator_t&lt;const V&gt;, const T*&gt;
      { return ranges::begin(<i>base_</i>); }
  
      constexpr auto end() requires (!<i>simple-view</i>&lt;V&gt;)
      { return sentinel&lt;false&gt;(ranges::end(<i>base_</i>), addressof(*<i>value_</i>)); }
  
      constexpr auto end() const
        requires range&lt;const V> &amp;&amp;
                 indirect_binary_predicate&lt;ranges::equal_to, iterator_t&lt;const V&gt;, const T*&gt;
      { return sentinel&lt;true&gt;(ranges::end(<i>base_</i>), addressof(*<i>value_</i>)); }
    };
  
    template&lt;class R, class T&gt;
      take_before_view(R&amp;&amp;, T) -> take_before_view&lt;views::all_t&lt;R&gt;, T&gt;;
  }
</pre>
          <pre>constexpr explicit take_before_view(V base, const T& value) requires copy_constructible&lt;T&gt;;</pre>
          <blockquote>
            <p>-1- <i>Effects</i>: Initializes <code><i>base_</i></code> with <code>std::move(base)</code> and
              <code><i>value_</i></code> with <code>value</code>.
            </p>
          </blockquote>
          <pre>constexpr explicit take_before_view(V base, T&& value);</pre>
          <blockquote>
            <p>-2- <i>Effects</i>: Initializes <code><i>base_</i></code> with <code>std::move(base)</code> and
              <code><i>value_</i></code> with <code>std::move(value)</code>.
            </p>
          </blockquote>
          <p>[26.7.?.3] Class template <code>take_before_view::<i>sentinel</i></code> [range.take.before.sentinel]</p>
          <pre>
  namespace std::ranges {
    template&lt;view V, move_constructible T&gt;
      requires input_range&lt;V&gt; &amp;&amp; is_object_v&lt;T&gt; &amp;&amp;
               indirect_binary_predicate&lt;ranges::equal_to, iterator_t&lt;V&gt;, const T*&gt;
    template&lt;bool Const&gt;
    class take_before_view&lt;V, T&gt;::<i>sentinel</i> {
      using Base = <i>maybe-const</i>&lt;Const, V&gt;;                       // <i>exposition only</i>

      sentinel_t&lt;<i>Base</i>&gt; <i>end_</i> = sentinel_t&lt;<i>Base</i>&gt;();                // <i>exposition only</i>
      conditional_t&lt;is_scalar_v&lt;T&gt;, T, const T*&gt; <i>value_</i>{};       // <i>exposition only</i>
      constexpr <i>sentinel</i>(sentinel_t&lt;<i>Base</i>&gt; end, const T* value);  // <i>exposition only</i>

    public:
      <i>sentinel</i>() = default;
      constexpr <i>sentinel</i>(sentinel&lt;!Const> s)
        requires Const && convertible_to&lt;sentinel_t&lt;V>, sentinel_t&lt;<i>Base</i>&gt;>;
  
      constexpr sentinel_t&lt;<i>Base</i>&gt; base() const { return <i>end_</i>; }
  
      friend constexpr bool operator==(const iterator_t&lt;<i>Base</i>&gt;&amp; x, const <i>sentinel</i>&amp; y);
  
      template&lt;bool OtherConst = !Const&gt;
        requires sentinel_for&lt;sentinel_t&lt;<i>Base</i>&gt;, iterator_t&lt;<i>maybe-const</i>&lt;OtherConst, V&gt;&gt;&gt;
      friend constexpr bool operator==(const iterator_t&lt;<i>maybe-const</i>&lt;OtherConst, V&gt;&gt;&amp; x,
                                       const <i>sentinel</i>&amp; y);
    };
  }
</pre>
          <pre>constexpr <i>sentinel</i>(sentinel_t&lt;<i>Base</i>&gt; end, const T* value);</pre>
          <blockquote>
            <p>-1- <i>Effects</i>: Initializes <code><i>end_</i></code> with <code>end</code>;
              initializes
              <code><i>value_</i></code> with <code>*value</code> if <code>is_scalar_v&lt;T&gt;</code> is
              <code>true</code> and
              <code>value</code> otherwise.
            </p>
          </blockquote>
          </pre>
          <pre>constexpr <i>sentinel</i>(sentinel&lt;!Const> s)
  requires Const && convertible_to&lt;sentinel_t&lt;V>, sentinel_t&lt;<i>Base</i>&gt;>;</pre>
          <blockquote>
            <p>-2- <i>Effects</i>: Initializes <code><i>end_</i></code> with <code>std::move(s.<i>end_</i>)</code> and
              <code><i>value_</i></code> with <code>s.<i>value_</i></code>.
            </p>
          </blockquote>
          <pre>friend constexpr bool operator==(const iterator_t&lt;<i>Base</i>&gt;&amp; x, const <i>sentinel</i>&amp; y);
  
template&lt;bool OtherConst = !Const&gt;
  requires sentinel_for&lt;sentinel_t&lt;<i>Base</i>&gt;, iterator_t&lt;<i>maybe-const</i>&lt;OtherConst, V&gt;&gt;&gt;
friend constexpr bool operator==(const iterator_t&lt;<i>maybe-const</i>&lt;OtherConst, V&gt;&gt;&amp; x,
                                 const <i>sentinel</i>&amp; y);</pre>
          <blockquote>
            <p>-3- <i>Returns</i>:
            <ol style="list-style-type: none">
              <li>
                <p>(3.1) &mdash; <code>
(y.<i>end_</i> == x || y.<i>value</i> == *x)</code> if <code>is_scalar_v&lt;T&gt;</code> is
                  <code>true</code>.
                </p>
              </li>
              <li>
                <p>(3.2) &mdash; Otherwise, (<code>y.<i>end_</i> == x || *y.<i>value</i> == *x</code>).</p>
              </li>
            </ol>
          </blockquote>
        </li>
        </blockquote>
        </blockquote>
        </li>
      </ol>
    </ol>
  </div>
  <a name="References"></a>
  <h2>References</h2>
  <dd>
  <dt id="biblio-p2760">[P2760R1]
  <dd>Barry Revzin. A Plan for C++26 Ranges. URL: <a
      href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2760r1.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2760r1.html</a>
</body>

</html>