String Prefix and Suffix Checking (original) (raw)

Document number: P0457R1
Date: 2017-07-16
Project: LWG
Reply-to: Mikhail Maltsev <maltsevm@gmail.com>
  1. Abstract
  2. History
    1. Changes from R0
  3. Motivation
  4. Prior work
  5. Design considerations
    1. Member function vs free function
    2. Overload set
    3. Passing by value vs passing by reference
  6. Wording
    1. basic_string
    2. basic_string_view
  7. References

1. Abstract

This paper proposes to add member functions starts_with andends_with to class templates basic_string andbasic_string_view. These functions check, whether or not a string starts with a given prefix or ends with a given suffix, respectively.

2. History

2.1. Changes from R0

3. Motivation

Checking, whether or not a given string starts with a given prefix (or ends with a given suffix) is a common task. In fact, standard libraries of many other programming languages include routines for performing such checks, for example:

And so on.

Also, some C++ libraries (other than the standard library) that implement a string type include such methods. For example, Qt library has classesQString [3] and QStringRef (analogous tostd::string_view) which have startsWith andendsWith member functions.

These functions are widely used. For example, the source code of a recent version of Qt (excluding third-party components) has 1193 occurrences ofstartsWith and 953 occurrences of endsWith. Other examples include Webkit (304 occurrences of startsWith and 142 occurrences ofendsWith) and LLVM (class StringRef, 113 matches forStartsWith and 38 matches for EndsWith).

4. Prior work

The basic_string_view class template included starts_withand ends_with up to revision 3 of the proposal (N3609 [4]). These two member functions were removed after LEWG discussion in Bristol. The main concerns were:

5. Design considerations

5.1. Member function vs free function

This proposal adds member functions starts_with andends_with to class templates basic_string andbasic_string_view. Another considered option was to add free functions to namespace std, but adding member functions is consistent with the existing API for compare. Besides, as the original proposal [5] mentioned, the order of parameters of a free function is ambiguous (starts_with(string, prefix) vs starts_with(prefix, string)).

5.2. Overload set

The original string_view proposal included the following overloads ofstarts_with:

// basic_string: bool starts_with(basic_string_view<charT, traits> s) const noexcept; bool starts_with(charT c) const noexcept; bool starts_with(const charT* s) const noexcept;

// basic_string_view: bool starts_with(const basic_string_view& prefix) const noexcept;

Qt offers the following overload set (for QString andQStringRef):

bool startsWith(const QString & s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const bool startsWith(const QLatin1String & s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const bool startsWith(const QChar & c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const bool startsWith(const QStringRef & s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const

This proposal includes the following overloads:

// basic_string: bool starts_with(charT c) const noexcept; bool starts_with(basic_string_view<charT, traits> s) const noexcept; bool starts_with(const charT* s) const noexcept;

// basic_string_view: constexpr bool starts_with(charT c) const noexcept; constexpr bool starts_with(basic_string_view<charT, traits> s) const noexcept; constexpr bool starts_with(const charT* s) const noexcept;

The overload overload for basic_string is not included, becausebasic_string has a non-explicit conversion operator tobasic_string_view.

5.3. Passing by value vs passing by reference

In accordance with the guidance from P0254R1 [5], objects of type basic_string_view are passed by value (not by reference).

6. Wording

6.1. basic_string

In [basic.string], add:

bool starts_with(basic_string_view<charT, traits> s) const noexcept; bool starts_with(charT c) const noexcept; bool starts_with(const charT* s) const noexcept; bool ends_with(basic_string_view<charT, traits> s) const noexcept; bool ends_with(charT c) const noexcept; bool ends_with(const charT* s) const noexcept;

After [string::compare] add:

basic_string::starts_with [string::starts_with]

bool starts_with(basic_string_view<charT, traits> s) const noexcept;

Effects: Equivalent to:return basic_string_view<charT, traits>(data(), size()).starts_with(s);
Complexity: O(s.size()).

bool starts_with(charT c) const noexcept;

Effects: Equivalent to:return basic_string_view<charT, traits>(data(), size()).starts_with(c);
Complexity: O(1).

bool starts_with(const charT* s) const noexcept;

Effects: Equivalent to:return basic_string_view<charT, traits>(data(), size()).starts_with(s);
Complexity: O(basic_string_view<charT, traits>(s).size()).

basic_string::ends_with [string::ends_with]

bool ends_with(basic_string_view<charT, traits> s) const noexcept;

Effects: Equivalent to:return basic_string_view<charT, traits>(data(), size()).ends_with(s);
Complexity: O(s.size()).

bool ends_with(charT c) const noexcept;

Effects: Equivalent to:return basic_string_view<charT, traits>(data(), size()).ends_with(c);
Complexity: O(1).

bool ends_with(const charT* s) const noexcept;

Effects: Equivalent to:return basic_string_view<charT, traits>(data(), size()).ends_with(s);
Complexity: O(basic_string_view<charT, traits>(s).size()).

6.2. basic_string_view

In [string.view.template], add:

constexpr bool starts_with(basic_string_view s) const noexcept; constexpr bool starts_with(charT c) const noexcept; constexpr bool starts_with(const charT* s) const noexcept; constexpr bool ends_with(basic_string_view s) const noexcept; constexpr bool ends_with(charT c) const noexcept; constexpr bool ends_with(const charT* s) const noexcept;

In [string.view.ops], add:

constexpr bool starts_with(basic_string_view s) const noexcept;

Effects: Equivalent to: return compare(0, npos, s) == 0;
Complexity: O(s.size()).

constexpr bool starts_with(charT c) const noexcept;

Effects: Equivalent to: return starts_with(basic_string_view(&c, 1));
Complexity: O(1).

constexpr bool starts_with(const charT* s) const noexcept;

Effects: Equivalent to: return starts_with(basic_string_view(s));
Complexity: O(basic_string_view(s).size()).

constexpr bool ends_with(basic_string_view s) const noexcept;

Effects: Equivalent to:return size() >= s.size() && compare(size() - s.size(), npos, s) == 0;
Complexity: O(s.size()).

constexpr bool end_with(charT c) const noexcept;

Effects: Equivalent to:return ends_with(basic_string_view(&c, 1))
Complexity: O(1).

constexpr bool ends_with(const charT* s) const noexcept;

Effects: Equivalent to: return ends_with(basic_string_view(s));
Complexity: O(basic_string_view(s).size()).

7. References

  1. The Python Standard Library. Built-in Types, https://docs.python.org/3.6/library/stdtypes.html#text-sequence-type-str
  2. Java™ Platform, Standard Edition 7 API Specification. Class String, https://docs.oracle.com/javase/7/docs/api/java/lang/String.html
  3. Qt Documentation. QString Class. http://doc.qt.io/qt-5/qstring.html
  4. string_view: a non-owning reference to a string, revision 3, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3609.html
  5. Integrating std::string_view and std::string, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0254r1.pdf