This is an automated email from the ASF dual-hosted git repository. zwoop pushed a commit to branch 7.1.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit d2b760c3c0918175dbf0b3511d35b9d92a95a5d9 Author: Jason Kenny <dragon...@live.com> AuthorDate: Wed Aug 30 13:38:21 2017 -0500 Add basic_string_view add some unit testing based on Catch --- lib/ts/Makefile.am | 16 +- lib/ts/string_view.h | 1216 +++++++++++++++++++++++++++++++++++++ lib/ts/unit-tests/main.cpp | 25 + lib/ts/unit-tests/string_view.cpp | 523 ++++++++++++++++ tests/{ => include}/catch.hpp | 0 5 files changed, 1777 insertions(+), 3 deletions(-) diff --git a/lib/ts/Makefile.am b/lib/ts/Makefile.am index 41ed45d..2e09e15 100644 --- a/lib/ts/Makefile.am +++ b/lib/ts/Makefile.am @@ -23,16 +23,16 @@ library_includedir=$(includedir)/ts library_include_HEADERS = apidefs.h noinst_PROGRAMS = mkdfa CompileParseRules -check_PROGRAMS = test_tsutil test_arena test_atomic test_freelist test_geometry test_List test_Map test_Vec test_X509HostnameValidator test_MemView +check_PROGRAMS = test_tsutil test_arena test_atomic test_freelist test_geometry test_List test_Map test_Vec test_X509HostnameValidator test_MemView test_tslib TESTS_ENVIRONMENT = LSAN_OPTIONS=suppressions=suppression.txt TESTS = $(check_PROGRAMS) -AM_CPPFLAGS += -I$(abs_top_srcdir)/lib - lib_LTLIBRARIES = libtsutil.la +AM_CPPFLAGS += -I$(abs_top_srcdir)/lib + libtsutil_la_LDFLAGS = -no-undefined -version-info @TS_LIBTOOL_VERSION@ libtsutil_la_LIBADD = \ @HWLOC_LIBS@ \ @@ -190,6 +190,7 @@ libtsutil_la_SOURCES = \ lockfile.cc \ signals.cc \ signals.h \ + string_view.h \ X509HostnameValidator.cc \ X509HostnameValidator.h @@ -239,6 +240,15 @@ test_tsutil_SOURCES = \ test_Regex.cc \ tests.cc +test_tslib_CPPFLAGS = $(AM_CPPFLAGS)\ + -I$(abs_top_srcdir)/tests/include + +# add you catch based test file here for tslib +test_tslib_LDADD = libtsutil.la +test_tslib_SOURCES = \ + unit-tests/main.cpp \ + unit-tests/string_view.cpp + CompileParseRules_SOURCES = CompileParseRules.cc clean-local: diff --git a/lib/ts/string_view.h b/lib/ts/string_view.h new file mode 100644 index 0000000..ff902bf --- /dev/null +++ b/lib/ts/string_view.h @@ -0,0 +1,1216 @@ +/** @file + + This is an implemetation of the std::string_view class for us to use + with c++11 and 14 until we can use the c++ 17 standard. This has a few overloads + to deal with some ats objects to help with migration work + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include <cstddef> +#include <type_traits> +#include <iterator> +#include <stdexcept> +#include <algorithm> +#include <utility> +#include <string> +#include <ostream> +#include <ts/ink_memory.h> + +#if __cplusplus < 201402 +#define CONSTEXPR14 inline +#else +#define CONSTEXPR14 constexpr +#endif + +namespace ts +{ +// forward declare class for iterator friend relationship +template <typename _Type, typename _CharTraits = std::char_traits<_Type>> class basic_string_view; + +///////////////////// +// the iterator + +namespace _private_ +{ + template <typename _CharTraits> class string_view_iterator + { // iterator for character buffer wrapper + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = typename _CharTraits::char_type; + using difference_type = std::ptrdiff_t; + using pointer = const value_type *; + using reference = const value_type &; + + constexpr string_view_iterator() noexcept = default; + + private: + friend basic_string_view<value_type, _CharTraits>; + + constexpr explicit string_view_iterator(const pointer rhs) noexcept : m_ptr(rhs) {} + + public: + constexpr reference operator*() const noexcept + { // return designated object + return *m_ptr; + } + + constexpr pointer operator->() const noexcept + { // return pointer to class object + return m_ptr; + } + + CONSTEXPR14 string_view_iterator &operator++() noexcept + { // preincrement + ++m_ptr; + return *this; + } + + CONSTEXPR14 string_view_iterator operator++(int)noexcept + { // postincrement + string_view_iterator tmp{*this}; + ++*this; + return tmp; + } + + CONSTEXPR14 string_view_iterator &operator--() noexcept + { // predecrement + --m_ptr; + return *this; + } + + CONSTEXPR14 string_view_iterator operator--(int)noexcept + { // postdecrement + string_view_iterator tmp{*this}; + --*this; + return tmp; + } + + CONSTEXPR14 string_view_iterator & + operator+=(const difference_type offset) noexcept + { // increment by integer + m_ptr += offset; + return *this; + } + + CONSTEXPR14 string_view_iterator + operator+(const difference_type offset) const noexcept + { // return this + integer + string_view_iterator tmp{*this}; + tmp += offset; + return tmp; + } + + CONSTEXPR14 string_view_iterator & + operator-=(const difference_type offset) noexcept + { // decrement by integer + m_ptr -= offset; + return *this; + } + + CONSTEXPR14 string_view_iterator + operator-(const difference_type offset) const noexcept + { // return this - integer + string_view_iterator tmp{*this}; + tmp -= offset; + return tmp; + } + + constexpr difference_type + operator-(const string_view_iterator &rhs) const noexcept + { // return difference of iterators + return m_ptr - rhs.m_ptr; + } + + constexpr reference operator[](const difference_type offset) const noexcept + { // subscript + return *(*this) + offset; + } + + constexpr bool + operator==(const string_view_iterator &rhs) const noexcept + { // test for iterator equality + return m_ptr == rhs.m_ptr; + } + + constexpr bool + operator!=(const string_view_iterator &rhs) const noexcept + { // test for iterator inequality + return !(*this == rhs); + } + + constexpr bool + operator<(const string_view_iterator &rhs) const noexcept + { // test if this < rhs + return m_ptr < rhs.m_ptr; + } + + constexpr bool + operator>(const string_view_iterator &rhs) const noexcept + { // test if this > rhs + return rhs < *this; + } + + constexpr bool + operator<=(const string_view_iterator &rhs) const noexcept + { // test if this <= rhs + return !(rhs < *this); + } + + constexpr bool + operator>=(const string_view_iterator &rhs) const noexcept + { // test if this >= rhs + return !(*this < rhs); + } + + private: + pointer m_ptr = nullptr; + }; +} + +template <typename _CharTraits> +CONSTEXPR14 _private_::string_view_iterator<_CharTraits> +operator+(const typename _private_::string_view_iterator<_CharTraits>::difference_type offset, + _private_::string_view_iterator<_CharTraits> rhs) noexcept +{ // return integer + _Right + rhs += offset; + return rhs; +} + +/// the main class + +template <typename _Type, typename _CharTraits> class basic_string_view +{ // wrapper for any kind of contiguous character buffer +public: + // some standard junk to say hey.. you are messing up something important.. stop it + static_assert(std::is_same<_Type, typename _CharTraits::char_type>::value, + "Bad char_traits for basic_string_view; " + "N4606 21.4.2 [string.view.template] \"the type traits::char_type shall name the same type as charT.\""); + + using traits_type = _CharTraits; + using value_type = _Type; + using pointer = _Type *; + using const_pointer = const _Type *; + using reference = _Type &; + using const_reference = const _Type &; + using const_iterator = _private_::string_view_iterator<_CharTraits>; + using iterator = const_iterator; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using reverse_iterator = const_reverse_iterator; + using size_type = std::size_t; + using difference_type = ptrdiff_t; + using self_type = basic_string_view<value_type, traits_type>; + static constexpr size_type npos{~0ULL}; + + constexpr basic_string_view() noexcept {} + + constexpr basic_string_view(basic_string_view const &) noexcept = default; + CONSTEXPR14 basic_string_view &operator=(basic_string_view const &) noexcept = default; + + /* implicit */ + // Note that with constexpr enabled and modern g++ and clang ( icpc) + // there is a optmization to strlen and traits_type::length for + // literals in which the compiler will replace it with the size + // at compile time. With c++ 17 the constexpr guarrentee + // that the literal length is optimized out + constexpr basic_string_view(const_pointer rhs) noexcept : m_data(rhs), m_size(traits_type::length(rhs)) {} + + constexpr basic_string_view(const_pointer rhs, const size_type length) noexcept // strengthened + : m_data(rhs), m_size(length) + { + } + + // std::string constructor + constexpr basic_string_view(std::string const &rhs) noexcept : m_data(rhs.data()), m_size(rhs.size()) {} + + // ats_scoped_str constructor + constexpr basic_string_view(ats_scoped_str const &rhs) noexcept : m_data(rhs.get()), m_size(traits_type::length(rhs.get())) {} + + // For iterator on string_view we don't need to deal with const and non-const as different types + // they are all const iterators as the string values are immutable + // keep in mind that the string view is mutable in what it points to + + constexpr const_iterator + begin() const noexcept + { // get the beginning of the range + return const_iterator(m_data); + } + + constexpr const_iterator + end() const noexcept + { // get the end of the range + return const_iterator(m_data + m_size); + } + + constexpr const_iterator + cbegin() const noexcept + { // get the beginning of the range + return begin(); + } + + constexpr const_iterator + cend() const noexcept + { // get the end of the range + return end(); + } + + constexpr const_reverse_iterator + rbegin() const noexcept + { // get the beginning of the reversed range + return const_reverse_iterator{end()}; + } + + constexpr const_reverse_iterator + rend() const noexcept + { // get the end of the reversed range + return const_reverse_iterator{begin()}; + } + + constexpr const_reverse_iterator + crbegin() const noexcept + { // get the beginning of the reversed range + return rbegin(); + } + + constexpr const_reverse_iterator + crend() const noexcept + { // get the end of the reversed range + return rend(); + } + + constexpr size_type + size() const noexcept + { // get the size of this basic_string_view + return m_size; + } + + constexpr size_type + length() const noexcept + { // get the size of this basic_string_view + return m_size; + } + + constexpr bool + empty() const noexcept + { // check whether this basic_string_view is empty + return m_size == 0; + } + + constexpr const_pointer + data() const noexcept + { // get the base pointer of this basic_string_view + // std says data does not have to have a NULL terminator + return m_data; + } + + constexpr size_type + max_size() const noexcept + { + // max size of byte we could make - 1 for npos divided my size of char + // to return the number of "character sized bytes" we can allocate + return (UINTPTR_MAX - 1) / sizeof(_Type); + } + + CONSTEXPR14 const_reference operator[](const size_type index) const // strengthened + { +// get character at offset +// assume index is in range +#ifdef _DEBUG + check_index_bound(index); // for debug +#endif + return m_data[index]; + } + + CONSTEXPR14 const_reference + at(const size_type index) const + { // get the character at offset or throw if that is out of range + check_index_bound(index); // add bound check + return m_data[index]; + } + + constexpr const_reference front() const noexcept // strengthened + { + // std is undefined for empty string + return m_data[0]; + } + + constexpr const_reference + back() const + { + // std is undefined for empty string + return m_data[m_size - 1]; + } + + CONSTEXPR14 void remove_prefix(const size_type length) noexcept // strengthened + { // chop off the beginning + auto tmp = std::min(length, m_size); + m_data += tmp; + m_size -= tmp; + } + + CONSTEXPR14 void remove_suffix(const size_type length) noexcept // strengthened + { // chop off the end + m_size -= std::min(length, m_size); + } + + CONSTEXPR14 void + swap(basic_string_view &rhs) noexcept + { // swap contents + const basic_string_view tmp{rhs}; // note: std::swap is not constexpr + rhs = *this; + *this = tmp; + } + + // possibly unsafe.. look for linux equal to a windows copy_s version if it exists + CONSTEXPR14 size_type + copy(_Type *const rhs, size_type length, const size_type offset = 0) const + { + check_offset_bound(offset); + length = std::min(length, m_size - offset); + traits_type::copy(rhs, m_data + offset, length); + return length; + } + + CONSTEXPR14 basic_string_view + substr(const size_type offset = 0, size_type length = npos) const + { + check_offset_bound(offset); + length = std::min(length, m_size - offset); + return basic_string_view(m_data + offset, length); + } + + // this is not a std function.. but is needed in some form for ==, != operators + // I could make this _equal to say don't call it.. but I won't + constexpr bool + _equal(const basic_string_view rhs) const noexcept + { + return m_size == rhs.m_size && traits_type::compare(m_data, rhs.m_data, m_size) == 0; + } + + constexpr bool + _equal(std::string const &rhs) const noexcept + { + return m_size == rhs.size() && traits_type::compare(m_data, rhs.data(), m_size) == 0; + } + + CONSTEXPR14 bool + _equal(value_type const *const rhs) const noexcept + { + self_type tmp(rhs); + return m_size == tmp.size() && traits_type::compare(m_data, tmp.data(), m_size) == 0; + } + + ////////////////////////////////////////////// + // Compare + + CONSTEXPR14 int + compare(const basic_string_view rhs) const noexcept + { + const int result = traits_type::compare(m_data, rhs.m_data, std::min(m_size, rhs.size())); + + if (result != 0) { + return result; + } + + if (m_size < rhs.m_size) { + return -1; + } + + if (m_size > rhs.m_size) { + return 1; + } + + return 0; + } + + constexpr int + compare(const size_type offset, const size_type length, const basic_string_view rhs) const + { + return substr(offset, length).compare(rhs); + } + + constexpr int + compare(const size_type offset, const size_type length, const basic_string_view rhs, const size_type rhsoffsetset, + const size_type rhs_length) const + { + return substr(offset, length).compare(rhs.substr(rhsoffsetset, rhs_length)); + } + + constexpr int + compare(const _Type *const rhs) const + { + return compare(basic_string_view(rhs)); + } + + constexpr int + compare(const size_type offset, const size_type length, const _Type *const rhs) const + { + return substr(offset, length).compare(basic_string_view(rhs)); + } + + constexpr int + compare(const size_type offset, const size_type length, const _Type *const rhs, const size_type rhs_length) const + { + return substr(offset, length).compare(basic_string_view(rhs, rhs_length)); + } + + ////////////////////// + // find -- string + + CONSTEXPR14 size_type find(const _Type *const rhs, const size_type offset, const size_type rhs_length) const + noexcept // strengthened + { + // do we have space to find the string given the offset + if (rhs_length > m_size || offset > m_size - rhs_length) { + // no match found + return npos; + } + + if (rhs_length == 0) { // empty string always matches to offset + return offset; + } + + // this is the point in which we can stop checking + const auto end_ptr = m_data + (m_size - rhs_length) + 1; + // start looking + for (auto curr = m_data + offset; curr < end_ptr; ++curr) { + // try to first char + curr = traits_type::find(curr, end_ptr - curr, *rhs); + if (!curr) { // didn't find first character; report failure + return npos; + } + // given we found it, see if it compares ( matches) + if (traits_type::compare(curr, rhs, rhs_length) == 0) { // found match + return curr - m_data; + } + // else try again till we run out of string space + } + // no match found + return npos; + } + + constexpr size_type + find(const basic_string_view rhs, const size_type offset = 0) const noexcept + { + return find(rhs.m_data, offset, rhs.size()); + } + + constexpr size_type find(const _Type *const rhs, const size_type offset = 0) const noexcept // strengthened + { + return find(rhs, offset, traits_type::length(rhs)); + } + + // character form + + CONSTEXPR14 size_type + find(const _Type c, const size_type offset = 0) const noexcept + { + if (offset < m_size) { + const auto found_at = traits_type::find(m_data + offset, m_size - offset, c); + if (found_at) { + return found_at - m_data; + } + } + // no match found + return npos; + } + + ///////////////////////////// + // rfind -- string + + CONSTEXPR14 size_type rfind(const _Type *const rhs, const size_type offset, const size_type rhs_length) const + noexcept // strengthened + { + if (rhs_length == 0) { + return std::min(offset, m_size); // empty string always matches + } + + if (rhs_length <= m_size) { + // room for match, look for it + for (auto curr = m_data + std::min(offset, m_size - rhs_length);; --curr) { + // do we have a match + if (traits_type::eq(*curr, *rhs) && traits_type::compare(curr, rhs, rhs_length) == 0) { + // found a match + return curr - m_data; + } + + // at beginning, no more chance for match? + if (curr == m_data) { + break; + } + } + } + + return npos; + } + + constexpr size_type rfind(const _Type *const rhs, const size_type offset = npos) const noexcept // strengthened + { + return rfind(rhs, offset, traits_type::length(rhs)); + } + + constexpr size_type + rfind(const basic_string_view rhs, const size_type offset = npos) const noexcept + { + return rfind(rhs.m_data, offset, rhs.m_size); + } + + // character version + + CONSTEXPR14 size_type + rfind(const _Type c, const size_type offset = npos) const noexcept + { + if (m_data != 0) { + for (auto curr = m_data + std::min(offset, m_size - 1);; --curr) { + if (traits_type::eq(*curr, c)) { + // found a match + return curr - m_data; + } + + if (curr == m_data) { + // at beginning, no more chances for match + break; + } + } + } + // no match found + return npos; + } + + ////////////////////////////////////// + // find_first_of + + CONSTEXPR14 size_type find_first_of(const _Type *const rhs, const size_type offset, const size_type rhs_length) const + noexcept // strengthened + { + if (rhs_length != 0 && offset < m_size) { + const auto _End = m_data + m_size; + for (auto curr = m_data + offset; curr < _End; ++curr) { + if (traits_type::find(rhs, rhs_length, *curr)) { + // found a match + return curr - m_data; + } + } + } + + // no match found + return npos; + } + + constexpr size_type find_first_of(const _Type *const rhs, const size_type offset = 0) const noexcept // strengthened + { + return find_first_of(rhs, offset, traits_type::length(rhs)); + } + + constexpr size_type + find_first_of(const basic_string_view rhs, const size_type offset = 0) const noexcept + { + return find_first_of(rhs.m_data, offset, rhs.m_size); + } + + // character version + + CONSTEXPR14 size_type + find_first_of(const _Type c, const size_type offset = 0) const noexcept + { + if (offset < m_size) { + const auto found_at = traits_type::find(m_data + offset, m_size - offset, c); + if (found_at) { + return found_at - m_data; + } + } + + // no match found + return npos; + } + + ////////////////////////////// + // find_last_of + + CONSTEXPR14 size_type find_last_of(const _Type *const rhs, const size_type offset, const size_type rhs_length) const + noexcept // strengthened + { + if (rhs_length != 0 && m_size != 0) { + for (auto curr = m_data + std::min(offset, m_size - 1);; --curr) { + if (traits_type::find(rhs, rhs_length, *curr)) { + // found a match + return curr - m_data; + } + + if (curr == m_data) { + // at beginning, no more chances for match + break; + } + } + } + + // no match found + return npos; + } + + constexpr size_type find_last_of(const _Type *const rhs, const size_type offset = npos) const noexcept // strengthened + { + return find_last_of(rhs, offset, traits_type::length(rhs)); + } + + constexpr size_type + find_last_of(const basic_string_view rhs, const size_type offset = npos) const noexcept + { + return find_last_of(rhs.m_data, offset, rhs.m_size); + } + + // character version + + CONSTEXPR14 size_type + find_last_of(const _Type c, const size_type offset = npos) const noexcept + { + if (m_size != 0) { // room for match, look for it + for (auto curr = m_data + std::min(offset, m_size - 1);; --curr) { + if (traits_type::eq(*curr, c)) { + // found a match + return curr - m_data; + } + + if (curr == m_data) { + // at beginning, no more chances for match + break; + } + } + } + + // no match found + return npos; + } + + ////////////////////////////// + // find_first_not_of + + CONSTEXPR14 size_type find_first_not_of(const _Type *const rhs, const size_type offset, const size_type rhs_length) const + noexcept // strengthened + { + if (offset < m_size) { + const auto _End = m_data + m_size; + for (auto curr = m_data + offset; curr < _End; ++curr) { + if (!traits_type::find(rhs, rhs_length, *curr)) { + // found a match + return curr - m_data; + } + } + } + + // no match found + return npos; + } + + constexpr size_type find_first_not_of(const _Type *const rhs, const size_type offset = 0) const noexcept // strengthened + { + return find_first_not_of(rhs, offset, traits_type::length(rhs)); + } + + constexpr size_type + find_first_not_of(const basic_string_view rhs, const size_type offset = 0) const noexcept + { + return find_first_not_of(rhs.m_data, offset, rhs.m_size); + } + + // character version + + CONSTEXPR14 size_type + find_first_not_of(const _Type c, const size_type offset = 0) const noexcept + { + if (offset < m_size) { + const auto _End = m_data + m_size; + for (auto curr = m_data + offset; curr < _End; ++curr) { + if (!traits_type::eq(*curr, c)) { + // found a match + return curr - m_data; + } + } + } + + // no match found + return npos; + } + + ////////////////////////////// + // find_last_not_of + + CONSTEXPR14 size_type find_last_not_of(const _Type *const rhs, const size_type offset, const size_type rhs_length) const + noexcept // strengthened + { + if (m_size != 0) { + for (auto curr = m_data + std::min(offset, m_size - 1);; --curr) { + if (!traits_type::find(rhs, rhs_length, *curr)) { + // found a match + return curr - m_data; + } + + if (curr == m_data) { + // at beginning, no more chances for match + break; + } + } + } + + // no match found + return npos; + } + + constexpr size_type find_last_not_of(const _Type *const rhs, const size_type offset = npos) const noexcept // strengthened + { + return find_last_not_of(rhs, offset, traits_type::length(rhs)); + } + + constexpr size_type + find_last_not_of(const basic_string_view rhs, const size_type offset = npos) const noexcept + { + return find_last_not_of(rhs.m_data, offset, rhs.m_size); + } + + // character version + + CONSTEXPR14 size_type + find_last_not_of(const _Type c, const size_type offset = npos) const noexcept + { + if (m_size != 0) { // room for match, look for it + for (auto curr = m_data + std::min(offset, m_size - 1);; --curr) { + if (!traits_type::eq(*curr, c)) { + // found a match + return curr - m_data; + } + + if (curr == m_data) { + // at beginning, no more chances for match + break; + } + } + } + // no match found + return npos; + } + +private: + CONSTEXPR14 void + check_offset_bound(size_type offset) const + { + // check that the offset is not greater than the size + if (offset > m_size) { + throw std::out_of_range("invalid string_view position"); + } + } + + CONSTEXPR14 void + check_index_bound(size_type index) const + { + // check that the offset is not greater than the size + if (index >= m_size) { + throw std::out_of_range("invalid string_view position"); + } + } + +private: + const_pointer m_data = nullptr; + size_type m_size = 0; +}; + +// operators for basic_string_view<> +// this has a c++11 compat version and a c++14/17 version that uses enable_if_t and some newer stuff to reduce the code +// Ideally we use the old version for c++11 compilers, newer version for c++14 compiler. For c++17 we should not need this file +// as we can use the builtin version then +#if __cplusplus < 201402 + +//////////////////////////// +// == +template <typename _Type, typename _Traits> +inline bool +operator==(basic_string_view<_Type, _Traits> const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return lhs._equal(rhs); +} +template <typename _Type, typename _Traits> +inline bool +operator==(std::string const &lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return rhs._equal(lhs); +} +template <typename _Type, typename _Traits> +inline bool +operator==(basic_string_view<_Type, _Traits> const lhs, std::string const &rhs) +{ + return lhs._equal(rhs); +} +template <typename _Type, typename _Traits> +inline bool +operator==(basic_string_view<_Type, _Traits> const lhs, char const *const rhs) +{ + return lhs.compare(rhs) == 0; +} +template <typename _Type, typename _Traits> +inline bool +operator==(char const *const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return rhs.compare(lhs) == 0; +} +//////////////////////////// +// != +template <typename _Type, typename _Traits> +inline bool +operator!=(basic_string_view<_Type, _Traits> const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return !lhs._equal(rhs); +} +template <typename _Type, typename _Traits> +inline bool +operator!=(std::string const &lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return !rhs._equal(lhs); +} +template <typename _Type, typename _Traits> +inline bool +operator!=(basic_string_view<_Type, _Traits> const lhs, std::string const &rhs) +{ + return !lhs._equal(rhs); +} +template <typename _Type, typename _Traits> +inline bool +operator!=(basic_string_view<_Type, _Traits> const lhs, char const *const rhs) +{ + return lhs.compare(rhs) != 0; +} +template <typename _Type, typename _Traits> +inline bool +operator!=(char const *const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return rhs.compare(lhs) != 0; +} +//////////////////////////// +// < +template <typename _Type, typename _Traits> +inline bool +operator<(basic_string_view<_Type, _Traits> const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return lhs.compare(rhs) < 0; +} +template <typename _Type, typename _Traits> +inline bool +operator<(std::string const &lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return lhs.compare(rhs) < 0; +} +template <typename _Type, typename _Traits> +inline bool +operator<(basic_string_view<_Type, _Traits> const lhs, std::string const &rhs) +{ + return lhs.compare(rhs) < 0; +} +template <typename _Type, typename _Traits> +inline bool +operator<(basic_string_view<_Type, _Traits> const lhs, char const *const rhs) +{ + return lhs.compare(rhs) < 0; +} +template <typename _Type, typename _Traits> +inline bool +operator<(char const *const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return rhs.compare(lhs) < 0; +} +//////////////////////////// +// > + +template <typename _Type, typename _Traits> +inline bool +operator>(basic_string_view<_Type, _Traits> const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return lhs.compare(rhs) > 0; +} +template <typename _Type, typename _Traits> +inline bool +operator>(std::string const &lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return lhs.compare(rhs) > 0; +} +template <typename _Type, typename _Traits> +inline bool +operator>(basic_string_view<_Type, _Traits> const lhs, std::string const &rhs) +{ + return lhs.compare(rhs) > 0; +} +template <typename _Type, typename _Traits> +inline bool +operator>(basic_string_view<_Type, _Traits> const lhs, char const *const rhs) +{ + return lhs.compare(rhs) > 0; +} +template <typename _Type, typename _Traits> +inline bool +operator>(char const *const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return rhs.compare(lhs) < 0; +} + +//////////////////////////// +// <= +template <typename _Type, typename _Traits> +inline bool +operator<=(basic_string_view<_Type, _Traits> const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return lhs.compare(rhs) <= 0; +} +template <typename _Type, typename _Traits> +inline bool +operator<=(std::string const &lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return lhs.compare(rhs) <= 0; +} +template <typename _Type, typename _Traits> +inline bool +operator<=(basic_string_view<_Type, _Traits> const lhs, std::string const &rhs) +{ + return lhs.compare(rhs) <= 0; +} +template <typename _Type, typename _Traits> +inline bool +operator<=(basic_string_view<_Type, _Traits> const lhs, char const *const rhs) +{ + return lhs.compare(rhs) <= 0; +} +template <typename _Type, typename _Traits> +inline bool +operator<=(char const *const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return rhs.compare(lhs) <= 0; +} +//////////////////////////// +// >= +template <typename _Type, typename _Traits> +inline bool +operator>=(basic_string_view<_Type, _Traits> const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return lhs.compare(rhs) >= 0; +} +template <typename _Type, typename _Traits> +inline bool +operator>=(std::string const &lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return lhs.compare(rhs) >= 0; +} +template <typename _Type, typename _Traits> +inline bool +operator>=(basic_string_view<_Type, _Traits> const lhs, std::string const &rhs) +{ + return lhs.compare(rhs) >= 0; +} +template <typename _Type, typename _Traits> +inline bool +operator>=(basic_string_view<_Type, _Traits> const lhs, char const *const rhs) +{ + return lhs.compare(rhs) >= 0; +} +template <typename _Type, typename _Traits> +inline bool +operator>=(char const *const lhs, basic_string_view<_Type, _Traits> const rhs) +{ + return rhs.compare(lhs) >= 0; +} + +#else +///////////////////////////////////////////////// +// this form is more functional than the above case which only deals with char* and std::string +// this form deal with convertable type correctly as is less code :) + +//////////////////////////// +// == +template <typename _Type, typename _Traits> +constexpr bool +operator==(const basic_string_view<_Type, _Traits> lhs, const basic_string_view<_Type, _Traits> rhs) noexcept +{ + return lhs._equal(rhs); +} + +// user conversion for stuff like std::string or char*, literals + +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator==(_OtherType &&lhs, const basic_string_view<_Type, _Traits> rhs) noexcept( + noexcept(basic_string_view<_Type, _Traits>(std::forward<_OtherType>(lhs)))) +{ + return rhs._equal(std::forward<_OtherType>(lhs)); +} + +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator==(const basic_string_view<_Type, _Traits> lhs, + _OtherType &&rhs) noexcept(noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(rhs))))) +{ + return lhs._equal(std::forward<_OtherType>(rhs)); +} + +/////////////////////////////// +// != +template <typename _Type, typename _Traits> +constexpr bool +operator!=(const basic_string_view<_Type, _Traits> lhs, const basic_string_view<_Type, _Traits> rhs) noexcept +{ + return !lhs._equal(rhs); +} + +// user conversion for stuff like std::string or char*, literals +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator!=(_OtherType &&lhs, const basic_string_view<_Type, _Traits> rhs) noexcept( + noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(lhs))))) +{ + return !rhs._equal(std::forward<_OtherType>(lhs)); +} + +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator!=(const basic_string_view<_Type, _Traits> lhs, + _OtherType &&rhs) noexcept(noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(rhs))))) +{ + return !lhs._equal(std::forward<_OtherType>(rhs)); +} + +/////////////////////////////// +// < +template <typename _Type, typename _Traits> +constexpr bool +operator<(const basic_string_view<_Type, _Traits> lhs, const basic_string_view<_Type, _Traits> rhs) noexcept +{ + return lhs.compare(rhs) < 0; +} + +// user conversion for stuff like std::string or char*, literals +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator<(_OtherType &&lhs, const basic_string_view<_Type, _Traits> rhs) noexcept( + noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(lhs))))) +{ // less-than compare objects convertible to basic_string_view instances + return basic_string_view<_Type, _Traits>(std::forward<_OtherType>(lhs)).compare(rhs) < 0; +} + +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator<(const basic_string_view<_Type, _Traits> lhs, + _OtherType &&rhs) noexcept(noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(rhs))))) +{ + return lhs.compare(std::forward<_OtherType>(rhs)) < 0; +} + +/////////////////////////////// +// > +template <typename _Type, typename _Traits> +constexpr bool +operator>(const basic_string_view<_Type, _Traits> lhs, const basic_string_view<_Type, _Traits> rhs) noexcept +{ + return lhs.compare(rhs) > 0; +} +// user conversion for stuff like std::string or char*, literals +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator>(_OtherType &&lhs, const basic_string_view<_Type, _Traits> rhs) noexcept( + noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(lhs))))) +{ + return basic_string_view<_Type, _Traits>(std::forward<_OtherType>(lhs)).compare(rhs) > 0; +} + +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator>(const basic_string_view<_Type, _Traits> lhs, + _OtherType &&rhs) noexcept(noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(rhs))))) +{ + return lhs.compare(std::forward<_OtherType>(rhs)) > 0; +} + +/////////////////////////////// +// <= +template <typename _Type, typename _Traits> +constexpr bool +operator<=(const basic_string_view<_Type, _Traits> lhs, const basic_string_view<_Type, _Traits> rhs) noexcept +{ + return lhs.compare(rhs) <= 0; +} +// user conversion for stuff like std::string or char*, literals +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator<=(_OtherType &&lhs, const basic_string_view<_Type, _Traits> rhs) noexcept( + noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(lhs))))) +{ + return basic_string_view<_Type, _Traits>(std::forward<_OtherType>(lhs)).compare(rhs) <= 0; +} + +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator<=(const basic_string_view<_Type, _Traits> lhs, + _OtherType &&rhs) noexcept(noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(rhs))))) +{ + return lhs.compare(std::forward<_OtherType>(rhs)) <= 0; +} + +/////////////////////////////// +// >= +template <typename _Type, typename _Traits> +constexpr bool +operator>=(const basic_string_view<_Type, _Traits> lhs, const basic_string_view<_Type, _Traits> rhs) noexcept +{ + return lhs.compare(rhs) >= 0; +} +// user conversion for stuff like std::string or char*, literals +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator>=(_OtherType &&lhs, const basic_string_view<_Type, _Traits> rhs) noexcept( + noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(lhs))))) +{ + return basic_string_view<_Type, _Traits>(std::forward<_OtherType>(lhs)).compare(rhs) >= 0; +} + +template <typename _Type, typename _Traits, typename _OtherType, + typename = std::enable_if_t<std::is_convertible<_OtherType, basic_string_view<_Type, _Traits>>::value>> +constexpr bool +operator>=(const basic_string_view<_Type, _Traits> lhs, + _OtherType &&rhs) noexcept(noexcept((basic_string_view<_Type, _Traits>(std::forward<_OtherType>(rhs))))) +{ + return lhs.compare(std::forward<_OtherType>(rhs)) >= 0; +} +#endif +// stream operator + +template <typename _Type, typename _Traits> +inline std::basic_ostream<_Type, _Traits> & +operator<<(std::basic_ostream<_Type, _Traits> &os, const basic_string_view<_Type, _Traits> lhs) +{ + return os.write(lhs.data(), lhs.size()); +} +using string_view = basic_string_view<char>; + +} // namespace ts diff --git a/lib/ts/unit-tests/main.cpp b/lib/ts/unit-tests/main.cpp new file mode 100644 index 0000000..72537d2 --- /dev/null +++ b/lib/ts/unit-tests/main.cpp @@ -0,0 +1,25 @@ +/** @file + + This file used for catch based tests. It is the main() stub. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/lib/ts/unit-tests/string_view.cpp b/lib/ts/unit-tests/string_view.cpp new file mode 100644 index 0000000..a49c5a0 --- /dev/null +++ b/lib/ts/unit-tests/string_view.cpp @@ -0,0 +1,523 @@ +/** @file + Test file for basic_string_view class + @section license License + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "catch.hpp" + +#ifndef _DEBUG +#define _DEBUG +#endif + +#include "string_view.h" +#include <iostream> +#include <string> +#include <vector> + +using namespace std; + +constexpr auto npos = ts::string_view::npos; + +// ======= test for string_view ======== +// test cases: +//[constructor] [operator] [type] [access] [capacity] [modifier] [operation] [compare] [find] + +TEST_CASE("constructor calls", "[string_view] [constructor]") +{ + SECTION("Literal look for NULL") + { + ts::string_view sv("hello"); + REQUIRE(sv.size() == 5); + REQUIRE(sv.length() == 5); + REQUIRE(sv.empty() == false); + REQUIRE(sv == "hello"); + } + + SECTION("operator =") + { + ts::string_view sv; + sv = "hello"; + REQUIRE(sv.size() == 5); + REQUIRE(sv.length() == 5); + REQUIRE(sv.empty() == false); + REQUIRE(sv == "hello"); + } + + SECTION("Literal with NULL") + { + ts::string_view sv("hello\0world"); + REQUIRE(sv.size() == 5); + REQUIRE(sv.length() == 5); + REQUIRE(sv.empty() == false); + REQUIRE(sv == "hello"); + } + + SECTION("Literal with NULL and size given") + { + ts::string_view sv("hello\0world", 11); + REQUIRE(sv.size() == 11); + REQUIRE(sv.length() == 11); + REQUIRE(sv.empty() == false); + REQUIRE(sv[6] == 'w'); + REQUIRE(sv == ts::string_view("hello\0world", 11)); + } + + SECTION("Literal length given") + { + ts::string_view sv("hello", 5); + REQUIRE(sv.size() == 5); + REQUIRE(sv.length() == 5); + REQUIRE(sv.empty() == false); + REQUIRE(sv == "hello"); + } + + SECTION("Literal length equal 0") + { + ts::string_view sv("hello", 0); + REQUIRE(sv.size() == 0); + REQUIRE(sv.length() == 0); + REQUIRE(sv.empty() == true); + REQUIRE(sv == ""); + } + + SECTION("constructor using std string") + { + string std_string = "hello"; + ts::string_view sv(std_string); + + REQUIRE(sv.size() == std_string.size()); + REQUIRE(sv.size() == std_string.size()); + REQUIRE(sv.empty() == false); + REQUIRE(sv == "hello"); + } + + SECTION("= operator") + { + string std_string = "hello"; + ts::string_view sv = std_string; + char str1[10] = "hello"; + ts::string_view sv2 = str1; + char const *str2 = "hello"; + ts::string_view sv3 = str2; + + REQUIRE(sv == "hello"); + REQUIRE(sv2 == "hello"); + REQUIRE(sv3 == "hello"); + } +} + +TEST_CASE("operators", "[string_view] [operator]") +{ + SECTION("==") + { + ts::string_view sv("hello"); + + char str1[10] = "hello"; + char const *str2 = "hello"; + string str3 = "hello"; + + REQUIRE(str2 == str3); + REQUIRE(str1 == str3); + + REQUIRE(sv == "hello"); + REQUIRE(sv == str1); + REQUIRE(sv == str2); + REQUIRE(sv == str3); + } + SECTION("!=") + { + ts::string_view sv("hello"); + + char str1[10] = "hhhhhhhhh"; + char const *str2 = "hella"; + string str3 = ""; + + REQUIRE(str2 != str3); + REQUIRE(str1 != str3); + + REQUIRE(sv != str1); + REQUIRE(sv != str2); + REQUIRE(sv != str3); + } + SECTION(">") + { + ts::string_view sv("hello"); + + char str1[10] = "a"; + char const *str2 = "abcdefg"; + string str3 = ""; + + REQUIRE(sv > str1); + REQUIRE(sv > str2); + REQUIRE(sv > str3); + } + SECTION("<") + { + ts::string_view sv("hello"); + + char str1[10] = "z"; + char const *str2 = "zaaaaaa"; + string str3 = "hellz"; + + REQUIRE(sv < str1); + REQUIRE(sv < str2); + REQUIRE(sv < str3); + } + SECTION(">=") + { + ts::string_view sv("hello"); + + char str1[10] = "hello"; + char const *str2 = "abcdefg"; + string str3 = ""; + + REQUIRE(sv >= str1); + REQUIRE(sv >= str2); + REQUIRE(sv >= str3); + } + SECTION("<=") + { + ts::string_view sv("hello"); + + char str1[10] = "hello"; + char const *str2 = "zaaaaaa"; + string str3 = "hellz"; + + REQUIRE(sv <= str1); + REQUIRE(sv <= str2); + REQUIRE(sv <= str3); + } +} + +TEST_CASE("Pass in type checking", "[string_view] [type]") +{ + SECTION("char [] type") + { + char str[10] = "hello"; + ts::string_view sv(str); + REQUIRE(sv == "hello"); + REQUIRE(sv.size() == 5); + REQUIRE(sv.empty() == false); + + char str2[10] = {}; + ts::string_view sv2(str2); + REQUIRE(sv2 == ""); + REQUIRE(sv2.empty() == true); + } + + SECTION("char * type") + { + char const *str = "hello"; + ts::string_view sv(str); + REQUIRE(sv == "hello"); + REQUIRE(sv.size() == 5); + REQUIRE(sv.empty() == false); + } + + SECTION("literal type") + { + ts::string_view sv("hello"); + REQUIRE(sv == "hello"); + } +} + +TEST_CASE("Access & iterators", "[string_view] [access]") +{ + SECTION("iterators: begin, end, rbegin, rend") + { + ts::string_view sv("abcde"); + + REQUIRE(*sv.begin() == 'a'); + REQUIRE(*sv.cbegin() == 'a'); + REQUIRE(*sv.end() == '\0'); + REQUIRE(*sv.cend() == '\0'); + REQUIRE(*sv.rbegin() == 'e'); + REQUIRE(*sv.crbegin() == 'e'); + REQUIRE(*sv.rend() == '\0'); + REQUIRE(*sv.crend() == '\0'); + + int n = 0; + for (auto it : sv) + { + REQUIRE(it == sv[n]); + n++; + } + } + + SECTION("access: [], at, front, back, data") + { + ts::string_view sv("abcde"); + REQUIRE(sv[0] == 'a'); + REQUIRE(sv[4] == 'e'); + + REQUIRE(sv.at(0) == 'a'); + REQUIRE(sv.at(4) == 'e'); + + REQUIRE(sv.front() == 'a'); + REQUIRE(sv.back() == 'e'); + + REQUIRE(sv.data()[1] == 'b'); + } + + SECTION("exception case") + { + ts::string_view sv("abcde"); + + REQUIRE_THROWS_AS(sv.at(100), std::out_of_range); + REQUIRE_THROWS_AS(sv.at(-1), std::out_of_range); + + REQUIRE_THROWS_AS(sv[100], std::out_of_range); + REQUIRE_THROWS_AS(sv[-1], std::out_of_range); + } +} + +TEST_CASE("Capacity", "[string_view] [capacity]") +{ + SECTION("empty string") + { + ts::string_view sv; + REQUIRE(sv.size() == 0); + REQUIRE(sv.length() == 0); + REQUIRE(sv.empty() == true); + REQUIRE(sv.max_size() == 0xfffffffffffffffe); + } + + SECTION("literal string") + { + ts::string_view sv("abcde"); + REQUIRE(sv.size() == 5); + REQUIRE(sv.length() == 5); + REQUIRE(sv.empty() == false); + REQUIRE(sv.max_size() == 0xfffffffffffffffe); + } +} + +TEST_CASE("Modifier", "[string_view] [modifier]") +{ + SECTION("remove prefix") + { + ts::string_view sv("abcde"); + + sv.remove_prefix(0); + REQUIRE(sv == "abcde"); + + sv.remove_prefix(3); + REQUIRE(sv == "de"); + + sv.remove_prefix(100); + REQUIRE(sv == ""); + } + + SECTION("remove suffix") + { + ts::string_view sv("abcde"); + + sv.remove_suffix(0); + REQUIRE(sv == "abcde"); + + sv.remove_suffix(3); + REQUIRE(sv == "ab"); + + sv.remove_suffix(100); + REQUIRE(sv == ""); + } + + SECTION("swap") + { + ts::string_view sv1("hello"); + ts::string_view sv2("world"); + + sv1.swap(sv2); + + REQUIRE(sv1 == "world"); + REQUIRE(sv2 == "hello"); + } +} + +TEST_CASE("Operations", "[string_view] [operation]") +{ + SECTION("copy") + { + //weird copy + + // char str[10]; + // ts::string_view sv("hello"); + // sv.copy(str, 6, 0); + // REQUIRE(str == "hello"); + } + SECTION("substr") + { + ts::string_view sv("hello"); + REQUIRE(sv.substr(0, 3) == "hel"); + REQUIRE(sv.substr(1, 3) == "ell"); + REQUIRE(sv.substr(0, 100) == "hello"); + } + SECTION("exception case") + { + ts::string_view sv("hello"); + REQUIRE_THROWS_AS(sv.substr(100, 0), std::out_of_range); + REQUIRE_THROWS_AS(sv.substr(-1, -1), std::out_of_range); + } +} + +TEST_CASE("Compare", "[string_view] [compare]") +{ + SECTION("compare pass in char") + { + ts::string_view sv("hello"); + REQUIRE(sv.compare("hello") == 0); + REQUIRE(sv.compare("hella") > 0); + REQUIRE(sv.compare("hellz") < 0); + REQUIRE(sv.compare("aaaaaaa") > 0); + REQUIRE(sv.compare("zzzzzzz") < 0); + REQUIRE(sv.compare("") > 0); + + ts::string_view sv2("hello"); + REQUIRE(sv2.compare(0, 3, "hel") == 0); + REQUIRE(sv2.compare(1, 3, "ello", 0, 3) == 0); + + ts::string_view sv3(""); + REQUIRE(sv3.compare("hello") < 0); + } + + SECTION("compare pass in string view") + { + ts::string_view sv("hello"); + ts::string_view sv_test1("hello"); + ts::string_view sv_test2("aello"); + ts::string_view sv_test3("zello"); + REQUIRE(sv.compare(sv_test1) == 0); + REQUIRE(sv.compare(sv_test2) > 0); + REQUIRE(sv.compare(sv_test3) < 0); + + ts::string_view sv2("hello"); + ts::string_view sv_test4("hel"); + ts::string_view sv_test5("ello"); + REQUIRE(sv.compare(0, 3, sv_test4) == 0); + REQUIRE(sv.compare(1, 3, sv_test5, 0, 3) == 0); + } + + SECTION("exception case") + { + ts::string_view sv("hello"); + REQUIRE_THROWS_AS(sv.compare(100, 1, "hel"), std::out_of_range); + REQUIRE_THROWS_AS(sv.compare(100, 100, "hel"), std::out_of_range); + REQUIRE_THROWS_AS(sv.compare(-1, -1, "hel"), std::out_of_range); + } +} + +TEST_CASE("Find", "[string_view] [find]") +{ + SECTION("find") + { + ts::string_view sv("abcdabcd"); + ts::string_view svtest("bcd"); + + REQUIRE(sv.find("abcdabcd", 100, 10) == npos); + + REQUIRE(sv.find('a') == 0); + REQUIRE(sv.find(svtest) == 1); + REQUIRE(sv.find(svtest, 2) == 5); + + REQUIRE(sv.find("bcd") == 1); + REQUIRE(sv.find("bcd", 6) == npos); + + REQUIRE(sv.find("bcdx", 0, 3) == 1); + REQUIRE(sv.find("bcdx", 0, 4) == npos); + + ts::string_view sv2; + REQUIRE(sv2.find('a') == npos); + } + + SECTION("rfind") + { + ts::string_view sv("abcdabcd"); + ts::string_view svtest("bcd"); + REQUIRE(sv.find('a') == 0); + REQUIRE(sv.rfind(svtest) == 5); + + REQUIRE(sv.rfind("bcd") == 5); + REQUIRE(sv.rfind("bcd", 3) == 1); + REQUIRE(sv.rfind("bcd", 0) == npos); + + REQUIRE(sv.rfind("bcdx", 3, 3) == 1); + REQUIRE(sv.rfind("bcdx", 3, 4) == npos); + } + + SECTION("find_first_of") + { + ts::string_view sv("abcdefgabcdefg"); + ts::string_view svtest("hijklma"); + + REQUIRE(sv.find_first_of('c') == 2); + + REQUIRE(sv.find_first_of(svtest) == 0); + REQUIRE(sv.find_first_of("hijklmb") == 1); + REQUIRE(sv.find_first_of("hijklmn") == npos); + REQUIRE(sv.find_first_of("hijkla", 1) == 7); + + REQUIRE(sv.find_first_of("hijkla", 1, 0) == npos); + REQUIRE(sv.find_first_of("hijkla", 1, 5) == npos); + REQUIRE(sv.find_first_of("hijkla", 1, 6) == 7); + } + + SECTION("find_last_of") + { + ts::string_view sv("abcdefgabcdefg"); + ts::string_view svtest("hijklma"); + + REQUIRE(sv.find_last_of('c') == 9); + + REQUIRE(sv.find_last_of(svtest) == 7); + REQUIRE(sv.find_last_of("hijklmb") == 8); + REQUIRE(sv.find_last_of("hijklmn") == npos); + + REQUIRE(sv.find_last_of("hijkla", 1, 0) == npos); + REQUIRE(sv.find_last_of("hijkla", 1, 5) == npos); + REQUIRE(sv.find_last_of("hijkla", 1, 6) == 0); + } + SECTION("find_first_not_of") + { + ts::string_view sv("abcdefg"); + ts::string_view svtest("abcdxyz"); + + REQUIRE(sv.find_first_not_of('x') == 0); + + REQUIRE(sv.find_first_not_of(svtest) == 4); + REQUIRE(sv.find_first_not_of("abcdxyz") == 4); + REQUIRE(sv.find_first_not_of("abcdefg") == npos); + + REQUIRE(sv.find_first_not_of("abcdxyz", 1, 0) == 1); + REQUIRE(sv.find_first_not_of("abcdxyz", 1, 5) == 4); + REQUIRE(sv.find_first_not_of("aaaaaaaa", 1, 5) == 1); + } + + SECTION("find_last_not_of") + { + ts::string_view sv("abcdefg"); + ts::string_view svtest("abcdxyz"); + + REQUIRE(sv.find_last_not_of('x') == 6); + + REQUIRE(sv.find_last_not_of(svtest) == 6); + REQUIRE(sv.find_last_not_of("abcdxyz") == 6); + REQUIRE(sv.find_last_not_of("abcdefg") == npos); + + REQUIRE(sv.find_last_not_of("abcdxyz", 1, 0) == 1); + REQUIRE(sv.find_last_not_of("abcdxyz", 1, 5) == npos); + REQUIRE(sv.find_last_not_of("aaaaaaaa", 1, 5) == 1); + } +} diff --git a/tests/catch.hpp b/tests/include/catch.hpp similarity index 100% rename from tests/catch.hpp rename to tests/include/catch.hpp -- To stop receiving notification emails like this one, please contact "commits@trafficserver.apache.org" <commits@trafficserver.apache.org>.