Commit e1c3146d authored by Dominik Charousset's avatar Dominik Charousset Committed by Dominik Charousset

Add C++17-compatible string_view class

parent eb1cc7b1
...@@ -103,6 +103,7 @@ set(LIBCAF_CORE_SRCS ...@@ -103,6 +103,7 @@ set(LIBCAF_CORE_SRCS
src/stream_aborter.cpp src/stream_aborter.cpp
src/stream_manager.cpp src/stream_manager.cpp
src/stream_priority.cpp src/stream_priority.cpp
src/string_view.cpp
src/stringification_inspector.cpp src/stringification_inspector.cpp
src/sync_request_bouncer.cpp src/sync_request_bouncer.cpp
src/term.cpp src/term.cpp
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <cstddef>
#include <iterator>
#include <limits>
#include <type_traits>
#include "caf/detail/comparable.hpp"
namespace caf {
namespace detail {
// Catches `std::string`, `std::string_view` and all classes mimicing those,
// but not `std::vector<char>` or other buffers.
template <class T>
struct is_string_like {
// SFINAE checks.
template <class U>
static bool sfinae(
const U* x,
// check if `(*x)[0]` returns `const char&`
typename std::enable_if<
std::is_same<
const char&,
decltype((*x)[0])
>::value
>::type* = nullptr,
// check if `x->size()` returns an integer
typename std::enable_if<
std::is_integral<
decltype(x->size())
>::value
>::type* = nullptr,
// check if `x->compare(*x)` is well-formed and returns an integer
// (distinguishes vectors from strings)
typename std::enable_if<
std::is_integral<
decltype(x->compare(*x))
>::value
>::type* = nullptr);
// SFINAE fallback.
static void sfinae(void*);
// Result of SFINAE test.
using result_type =
decltype(sfinae(static_cast<typename std::decay<T>::type*>(nullptr)));
// Trait result.
static constexpr bool value = std::is_same<bool, result_type>::value;
};
} // namespace detail
/// Drop-in replacement for C++17 std::string_view.
class string_view : detail::comparable<string_view> {
public:
// -- member types -----------------------------------------------------------
using value_type = char;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using const_iterator = const_pointer;
using iterator = const_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using reverse_iterator = const_reverse_iterator;
using size_type = size_t;
using difference_type = ptrdiff_t;
// -- constants --------------------------------------------------------------
static constexpr size_type npos = std::numeric_limits<size_type>::max();
// -- constructors, destructors, and assignment operators --------------------
constexpr string_view() noexcept : data_(nullptr), size_(0) {
// nop
}
constexpr string_view(const char* cstr, size_t length) noexcept
: data_(cstr),
size_(length) {
// nop
}
template <size_t N>
constexpr string_view(const char (&cstr)[N]) noexcept
: data_(cstr),
size_(N - 1) {
static_assert(N > 0, "");
}
constexpr string_view(const string_view&) noexcept = default;
template <
class T,
class = typename std::enable_if<detail::is_string_like<T>::value>::type
>
string_view(const T& str) noexcept {
auto len = str.size();
if (len == 0) {
data_ = nullptr;
size_ = 0;
} else {
data_ = &(str[0]);
size_ = str.size();
}
}
string_view& operator=(const string_view&) noexcept = default;
// -- capacity ---------------------------------------------------------------
constexpr size_type size() const noexcept {
return size_;
}
constexpr size_type length() const noexcept {
return size_;
}
constexpr size_type max_size() const noexcept {
return std::numeric_limits<size_type>::max();
}
constexpr bool empty() const noexcept {
return size_ == 0;
}
// -- iterator access --------------------------------------------------------
constexpr const_iterator begin() const noexcept {
return data_;
}
constexpr const_iterator end() const noexcept {
return data_ + size_;
}
constexpr const_iterator cbegin() const noexcept {
return begin();
}
constexpr const_iterator cend() const noexcept {
return end();
}
const_reverse_iterator rbegin() const noexcept;
const_reverse_iterator rend() const noexcept;
const_reverse_iterator crbegin() const noexcept;
const_reverse_iterator crend() const noexcept;
// -- element access ---------------------------------------------------------
constexpr const_reference operator[](size_type pos) const {
return data_[pos];
}
const_reference at(size_type pos) const;
constexpr const_reference front() const {
return *data_;
}
constexpr const_reference back() const {
return data_[size_ - 1];
}
constexpr const_pointer data() const noexcept {
return data_;
}
// -- modifiers --------------------------------------------------------------
void remove_prefix(size_type n);
void remove_suffix(size_type n);
void assign(const_pointer data, size_type len);
// -- algortihms -------------------------------------------------------------
size_type copy(pointer dest, size_type n, size_type pos = 0) const;
string_view substr(size_type pos = 0, size_type n = npos) const noexcept;
int compare(string_view s) const noexcept;
int compare(size_type pos1, size_type n1, string_view str) const noexcept;
int compare(size_type pos1, size_type n1, string_view str,
size_type pos2, size_type n2) const noexcept;
int compare(const_pointer str) const noexcept;
int compare(size_type pos, size_type n, const_pointer str) const noexcept;
int compare(size_type pos1, size_type n1,
const_pointer s, size_type n2) const noexcept;
size_type find(string_view str, size_type pos = 0) const noexcept;
size_type find(value_type ch, size_type pos = 0) const noexcept;
size_type find(const_pointer str, size_type pos, size_type n) const noexcept;
size_type find(const_pointer str, size_type pos = 0) const noexcept;
size_type rfind(string_view str, size_type pos = npos) const noexcept;
size_type rfind(value_type ch, size_type pos = npos) const noexcept;
size_type rfind(const_pointer str, size_type pos, size_type n) const noexcept;
size_type rfind(const_pointer str, size_type pos = npos) const noexcept;
size_type find_first_of(string_view str, size_type pos = 0) const noexcept;
size_type find_first_of(value_type ch, size_type pos = 0) const noexcept;
size_type find_first_of(const_pointer str, size_type pos,
size_type n) const noexcept;
size_type find_first_of(const_pointer str, size_type pos = 0) const noexcept;
size_type find_last_of(string_view str, size_type pos = npos) const noexcept;
size_type find_last_of(value_type ch, size_type pos = npos) const noexcept;
size_type find_last_of(const_pointer str, size_type pos,
size_type n) const noexcept;
size_type find_last_of(const_pointer str,
size_type pos = npos) const noexcept;
size_type find_first_not_of(string_view str,
size_type pos = 0) const noexcept;
size_type find_first_not_of(value_type ch, size_type pos = 0) const noexcept;
size_type find_first_not_of(const_pointer str, size_type pos,
size_type n) const noexcept;
size_type find_first_not_of(const_pointer str,
size_type pos = 0) const noexcept;
size_type find_last_not_of(string_view str,
size_type pos = npos) const noexcept;
size_type find_last_not_of(value_type ch,
size_type pos = npos) const noexcept;
size_type find_last_not_of(const_pointer str, size_type pos,
size_type n) const noexcept;
size_type find_last_not_of(const_pointer str,
size_type pos = npos) const noexcept;
private:
const char* data_;
size_t size_;
};
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/string_view.hpp"
#include <algorithm>
#include <cstring>
#include <cstring>
#include <stdexcept>
#include "caf/config.hpp"
namespace {
using size_type = caf::string_view::size_type;
} // namespace anonymous
namespace caf {
// -- iterator access ----------------------------------------------------------
string_view::const_reverse_iterator string_view::rbegin() const noexcept {
return reverse_iterator{end()};
}
string_view::const_reverse_iterator string_view::rend() const noexcept {
return reverse_iterator{begin()};
}
string_view::const_reverse_iterator string_view::crbegin() const noexcept {
return rbegin();
}
string_view::const_reverse_iterator string_view::crend() const noexcept {
return rend();
}
// -- element access -----------------------------------------------------------
string_view::const_reference string_view::at(size_type pos) const {
if (pos < size_)
return data_[pos];
CAF_RAISE_ERROR("string_view::at out of range");
}
// -- modifiers ----------------------------------------------------------------
void string_view::remove_prefix(size_type n) {
if (n < size()) {
data_ += n;
size_ -= n;
} else {
size_ = 0;
}
}
void string_view::remove_suffix(size_type n) {
if (n < size())
size_ -= n;
else
size_ = 0;
}
void string_view::assign(const_pointer data, size_type len) {
data_ = data;
size_ = len;
}
// -- algortihms ---------------------------------------------------------------
string_view::size_type string_view::copy(pointer dest, size_type n,
size_type pos) const {
if (pos > size_)
CAF_RAISE_ERROR("string_view::copy out of range");
auto first = begin() + pos;
auto end = first + std::min(n, size() - pos);
auto cpy_end = std::copy(first, end, dest);
return static_cast<size_type>(std::distance(dest, cpy_end));
}
string_view string_view::substr(size_type pos, size_type n) const noexcept {
if (pos >= size())
return {};
return {data_ + pos, std::min(size_ - pos, n)};
}
int string_view::compare(string_view str) const noexcept {
return strncmp(data(), str.data(), std::min(size(), str.size()));
}
int string_view::compare(size_type pos1, size_type n1,
string_view str) const noexcept {
return substr(pos1, n1).compare(str);
}
int string_view::compare(size_type pos1, size_type n1, string_view str,
size_type pos2, size_type n2) const noexcept {
return substr(pos1, n1).compare(str.substr(pos2, n2));
}
int string_view::compare(const_pointer str) const noexcept {
return strncmp(data(), str, size());
}
int string_view::compare(size_type pos, size_type n,
const_pointer str) const noexcept {
return substr(pos, n).compare(str);
}
int string_view::compare(size_type pos1, size_type n1,
const_pointer str, size_type n2) const noexcept {
return substr(pos1, n1).compare(string_view{str, n2});
}
size_type string_view::find(string_view str, size_type pos) const noexcept {
string_view tmp;
if (pos < size_)
tmp.assign(data_ + pos, size_ - pos);
auto first = tmp.begin();
auto last = tmp.end();
auto i = std::search(first, last, str.begin(), str.end());
if (i != last)
return static_cast<size_type>(std::distance(first, i)) + pos;
return npos;
}
size_type string_view::find(value_type ch, size_type pos) const noexcept {
return find(string_view{&ch, 1}, pos);
}
size_type string_view::find(const_pointer str, size_type pos,
size_type n) const noexcept {
return find(string_view{str, n}, pos);
}
size_type string_view::find(const_pointer str, size_type pos) const noexcept {
return find(string_view{str, strlen(str)}, pos);
}
size_type string_view::rfind(string_view str, size_type pos) const noexcept {
if (size() < str.size())
return npos;
if (str.empty())
return std::min(size(), pos);
string_view tmp{data_, std::min(size() - str.size(), pos) + str.size()};
auto first = tmp.begin();
auto last = tmp.end();
auto i = std::find_end(first, last, str.begin(), str.end());
return i != last ? static_cast<size_type>(std::distance(first, i)) : npos;
}
size_type string_view::rfind(value_type ch, size_type pos) const noexcept {
return rfind(string_view{&ch, 1}, pos);
}
size_type string_view::rfind(const_pointer str, size_type pos,
size_type n) const noexcept {
return rfind(string_view{str, n}, pos);
}
size_type string_view::rfind(const_pointer str, size_type pos) const noexcept {
return rfind(string_view{str, strlen(str)}, pos);
}
size_type string_view::find_first_of(string_view str,
size_type pos) const noexcept {
if (empty() || str.empty())
return npos;
if (pos >= size())
return npos;
if (str.size() == 1)
return find(str.front(), pos);
string_view tmp{data_ + pos, size_ - pos};
auto first = tmp.begin();
auto last = tmp.end();
auto i = std::find_first_of(first, last, str.begin(), str.end());
return i != last ? static_cast<size_type>(std::distance(first, i)) + pos
: npos;
}
size_type string_view::find_first_of(value_type ch,
size_type pos) const noexcept {
return find(ch, pos);
}
size_type string_view::find_first_of(const_pointer str, size_type pos,
size_type n) const noexcept {
return find_first_of(string_view{str, n}, pos);
}
size_type string_view::find_first_of(const_pointer str,
size_type pos) const noexcept {
return find_first_of(string_view{str, strlen(str)}, pos);
}
size_type string_view::find_last_of(string_view str,
size_type pos) const noexcept {
string_view tmp{data_, pos < size_ ? pos + 1 : size_};
auto result = tmp.find_first_of(str);
if (result == npos)
return npos;
for (;;) {
auto next = tmp.find_first_of(str, result + 1);
if (next == npos)
return result;
result = next;
}
}
size_type string_view::find_last_of(value_type ch,
size_type pos) const noexcept {
return rfind(ch, pos);
}
size_type string_view::find_last_of(const_pointer str, size_type pos,
size_type n) const noexcept {
return find_last_of(string_view{str, n}, pos);
}
size_type string_view::find_last_of(const_pointer str,
size_type pos) const noexcept {
return find_last_of(string_view{str, strlen(str)}, pos);
}
size_type string_view::find_first_not_of(string_view str,
size_type pos) const noexcept {
if (str.size() == 1)
return find_first_not_of(str.front(), pos);
if (pos >= size())
return npos;
auto pred = [&](value_type x) { return str.find(x) == npos; };
string_view tmp{data_ + pos, size_ - pos};
auto first = tmp.begin();
auto last = tmp.end();
auto i = std::find_if(first, last, pred);
return i != last ? static_cast<size_type>(std::distance(first, i)) + pos
: npos;
}
size_type string_view::find_first_not_of(value_type ch,
size_type pos) const noexcept {
if (pos >= size())
return npos;
auto pred = [=](value_type x) { return x != ch; };
string_view tmp{data_ + pos, size_ - pos};
auto first = tmp.begin();
auto last = tmp.end();
auto i = std::find_if(first, last, pred);
return i != last ? static_cast<size_type>(std::distance(first, i)) + pos
: npos;
}
size_type string_view::find_first_not_of(const_pointer str, size_type pos,
size_type n) const noexcept {
return find_first_not_of(string_view{str, n}, pos);
}
size_type string_view::find_first_not_of(const_pointer str,
size_type pos) const noexcept {
return find_first_not_of(string_view{str, strlen(str)}, pos);
}
size_type string_view::find_last_not_of(string_view str,
size_type pos) const noexcept {
string_view tmp{data_, pos < size_ ? pos + 1 : size_};
auto result = tmp.find_first_not_of(str);
if (result == npos)
return npos;
for (;;) {
auto next = tmp.find_first_not_of(str, result + 1);
if (next == npos)
return result;
result = next;
}
}
size_type string_view::find_last_not_of(value_type ch,
size_type pos) const noexcept {
return find_last_not_of(string_view{&ch, 1}, pos);
}
size_type string_view::find_last_not_of(const_pointer str, size_type pos,
size_type n) const noexcept {
return find_last_not_of(string_view{str, n}, pos);
}
size_type string_view::find_last_not_of(const_pointer str,
size_type pos) const noexcept {
return find_last_not_of(string_view{str, strlen(str)}, pos);
}
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/config.hpp"
#define CAF_SUITE string_view
#include "caf/test/dsl.hpp"
#include "caf/string_view.hpp"
using namespace caf;
namespace {
struct fixture {
};
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(string_view_tests, fixture)
CAF_TEST(default construction) {
string_view x;
string_view y;
CAF_CHECK(x.empty());
CAF_CHECK_EQUAL(x.size(), 0u);
CAF_CHECK_EQUAL(x.data(), nullptr);
CAF_CHECK_EQUAL(y, y);
}
CAF_TEST(cstring conversion) {
string_view x = "abc";
CAF_CHECK_EQUAL(x.size(), 3u);
CAF_CHECK_EQUAL(x[0], 'a');
CAF_CHECK_EQUAL(x[1], 'b');
CAF_CHECK_EQUAL(x[2], 'c');
CAF_CHECK_EQUAL(x, "abc");
x = "def";
CAF_CHECK_NOT_EQUAL(x, "abc");
CAF_CHECK_EQUAL(x, "def");
}
CAF_TEST(string conversion) {
std::string x = "abc";
string_view y;
y = x;
CAF_CHECK_EQUAL(x, y);
auto f = [&](string_view z) {
CAF_CHECK_EQUAL(x, z);
};
f(x);
}
CAF_TEST(substrings) {
string_view x = "abcdefghi";
CAF_CHECK(x.remove_prefix(3), "defghi");
CAF_CHECK(x.remove_suffix(3), "abcdef");
CAF_CHECK(x.substr(3, 3), "def");
CAF_CHECK(x.remove_prefix(9), "");
CAF_CHECK(x.remove_suffix(9), "");
CAF_CHECK(x.substr(9), "");
CAF_CHECK(x.substr(0, 0), "");
}
CAF_TEST(compare) {
// testees
string_view x = "abc";
string_view y = "bcd";
string_view z = "cde";
// x.compare full strings
CAF_CHECK(x.compare("abc") == 0);
CAF_CHECK(x.compare(y) < 0);
CAF_CHECK(x.compare(z) < 0);
// y.compare full strings
CAF_CHECK(y.compare(x) > 0);
CAF_CHECK(y.compare("bcd") == 0);
CAF_CHECK(y.compare(z) < 0);
// z.compare full strings
CAF_CHECK(z.compare(x) > 0);
CAF_CHECK(z.compare(y) > 0);
CAF_CHECK(z.compare("cde") == 0);
// x.compare substrings
CAF_CHECK(x.compare(0, 3, "abc") == 0);
CAF_CHECK(x.compare(1, 2, y, 0, 2) == 0);
CAF_CHECK(x.compare(2, 1, z, 0, 1) == 0);
CAF_CHECK(x.compare(2, 1, z, 0, 2) == 0);
}
CAF_TEST(copy) {
char buf[10];
string_view str = "hello";
auto n = str.copy(buf, str.size());
CAF_CHECK_EQUAL(n, 5u);
buf[n] = '\0';
CAF_CHECK_EQUAL(str, string_view(buf, n));
CAF_CHECK(strcmp("hello", buf) == 0);
n = str.copy(buf, 10, 3);
buf[n] = '\0';
CAF_CHECK_EQUAL(string_view(buf, n), "lo");
CAF_CHECK(strcmp("lo", buf) == 0);
}
CAF_TEST(find) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abcdef";
std::string y = "abcdef";
CAF_CHECK_EQUAL(x.find('a'), y.find('a'));
CAF_CHECK_EQUAL(x.find('b'), y.find('b'));
CAF_CHECK_EQUAL(x.find('g'), y.find('g'));
CAF_CHECK_EQUAL(x.find('a', 1), y.find('a', 1));
CAF_CHECK_EQUAL(x.find("a"), y.find("a"));
CAF_CHECK_EQUAL(x.find("bc"), y.find("bc"));
CAF_CHECK_EQUAL(x.find("ce"), y.find("ce"));
CAF_CHECK_EQUAL(x.find("bc", 1), y.find("bc", 1));
CAF_CHECK_EQUAL(x.find("bc", 1, 0), y.find("bc", 1, 0));
CAF_CHECK_EQUAL(x.find("bc", 0, 1), y.find("bc", 0, 1));
CAF_CHECK_EQUAL(x.find("bc", 2, 10), y.find("bc", 2, 10));
}
CAF_TEST(rfind) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abccba";
std::string y = "abccba";
CAF_CHECK_EQUAL(x.rfind('a'), y.rfind('a'));
CAF_CHECK_EQUAL(x.rfind('b'), y.rfind('b'));
CAF_CHECK_EQUAL(x.rfind('g'), y.rfind('g'));
CAF_CHECK_EQUAL(x.rfind('a', 1), y.rfind('a', 1));
CAF_CHECK_EQUAL(x.rfind("a"), y.rfind("a"));
CAF_CHECK_EQUAL(x.rfind("bc"), y.rfind("bc"));
CAF_CHECK_EQUAL(x.rfind("ce"), y.rfind("ce"));
CAF_CHECK_EQUAL(x.rfind("bc", 1), y.rfind("bc", 1));
CAF_CHECK_EQUAL(x.rfind("bc", 1, 0), y.rfind("bc", 1, 0));
CAF_CHECK_EQUAL(x.rfind("bc", 0, 1), y.rfind("bc", 0, 1));
CAF_CHECK_EQUAL(x.rfind("bc", 2, 10), y.rfind("bc", 2, 10));
}
CAF_TEST(find_first_of) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abcdef";
std::string y = "abcdef";
CAF_CHECK_EQUAL(x.find_first_of('a'), y.find_first_of('a'));
CAF_CHECK_EQUAL(x.find_first_of('b'), y.find_first_of('b'));
CAF_CHECK_EQUAL(x.find_first_of('g'), y.find_first_of('g'));
CAF_CHECK_EQUAL(x.find_first_of('a', 1), y.find_first_of('a', 1));
CAF_CHECK_EQUAL(x.find_first_of("a"), y.find_first_of("a"));
CAF_CHECK_EQUAL(x.find_first_of("bc"), y.find_first_of("bc"));
CAF_CHECK_EQUAL(x.find_first_of("ce"), y.find_first_of("ce"));
CAF_CHECK_EQUAL(x.find_first_of("bc", 1), y.find_first_of("bc", 1));
CAF_CHECK_EQUAL(x.find_first_of("bc", 1, 0), y.find_first_of("bc", 1, 0));
CAF_CHECK_EQUAL(x.find_first_of("bc", 0, 1), y.find_first_of("bc", 0, 1));
CAF_CHECK_EQUAL(x.find_first_of("bc", 2, 10), y.find_first_of("bc", 2, 10));
}
CAF_TEST(find_last_of) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abcdef";
std::string y = "abcdef";
CAF_CHECK_EQUAL(x.find_last_of('a'), y.find_last_of('a'));
CAF_CHECK_EQUAL(x.find_last_of('b'), y.find_last_of('b'));
CAF_CHECK_EQUAL(x.find_last_of('g'), y.find_last_of('g'));
CAF_CHECK_EQUAL(x.find_last_of('a', 1), y.find_last_of('a', 1));
CAF_CHECK_EQUAL(x.find_last_of("a"), y.find_last_of("a"));
CAF_CHECK_EQUAL(x.find_last_of("bc"), y.find_last_of("bc"));
CAF_CHECK_EQUAL(x.find_last_of("ce"), y.find_last_of("ce"));
CAF_CHECK_EQUAL(x.find_last_of("bc", 1), y.find_last_of("bc", 1));
CAF_CHECK_EQUAL(x.find_last_of("bc", 1, 0), y.find_last_of("bc", 1, 0));
CAF_CHECK_EQUAL(x.find_last_of("bc", 0, 1), y.find_last_of("bc", 0, 1));
CAF_CHECK_EQUAL(x.find_last_of("bc", 2, 10), y.find_last_of("bc", 2, 10));
}
CAF_TEST(find_first_not_of) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abcdef";
std::string y = "abcdef";
CAF_CHECK_EQUAL(x.find_first_not_of('a'), y.find_first_not_of('a'));
CAF_CHECK_EQUAL(x.find_first_not_of('b'), y.find_first_not_of('b'));
CAF_CHECK_EQUAL(x.find_first_not_of('g'), y.find_first_not_of('g'));
CAF_CHECK_EQUAL(x.find_first_not_of('a', 1), y.find_first_not_of('a', 1));
CAF_CHECK_EQUAL(x.find_first_not_of("a"), y.find_first_not_of("a"));
CAF_CHECK_EQUAL(x.find_first_not_of("bc"), y.find_first_not_of("bc"));
CAF_CHECK_EQUAL(x.find_first_not_of("ce"), y.find_first_not_of("ce"));
CAF_CHECK_EQUAL(x.find_first_not_of("bc", 1), y.find_first_not_of("bc", 1));
CAF_CHECK_EQUAL(x.find_first_not_of("bc", 1, 0),
y.find_first_not_of("bc", 1, 0));
CAF_CHECK_EQUAL(x.find_first_not_of("bc", 0, 1),
y.find_first_not_of("bc", 0, 1));
CAF_CHECK_EQUAL(x.find_first_not_of("bc", 2, 10),
y.find_first_not_of("bc", 2, 10));
}
CAF_TEST(find_last_not_of) {
// Check whether string_view behaves exactly like std::string.
string_view x = "abcdef";
std::string y = "abcdef";
CAF_CHECK_EQUAL(x.find_last_not_of('a'), y.find_last_not_of('a'));
CAF_CHECK_EQUAL(x.find_last_not_of('b'), y.find_last_not_of('b'));
CAF_CHECK_EQUAL(x.find_last_not_of('g'), y.find_last_not_of('g'));
CAF_CHECK_EQUAL(x.find_last_not_of('a', 1), y.find_last_not_of('a', 1));
CAF_CHECK_EQUAL(x.find_last_not_of("a"), y.find_last_not_of("a"));
CAF_CHECK_EQUAL(x.find_last_not_of("bc"), y.find_last_not_of("bc"));
CAF_CHECK_EQUAL(x.find_last_not_of("ce"), y.find_last_not_of("ce"));
CAF_CHECK_EQUAL(x.find_last_not_of("bc", 1), y.find_last_not_of("bc", 1));
CAF_CHECK_EQUAL(x.find_last_not_of("bc", 1, 0),
y.find_last_not_of("bc", 1, 0));
CAF_CHECK_EQUAL(x.find_last_not_of("bc", 0, 1),
y.find_last_not_of("bc", 0, 1));
CAF_CHECK_EQUAL(x.find_last_not_of("bc", 2, 10),
y.find_last_not_of("bc", 2, 10));
}
CAF_TEST_FIXTURE_SCOPE_END()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment