mirror of
https://github.com/zebrajr/pytorch.git
synced 2025-12-06 12:20:52 +01:00
c10::string_view (#26616)
Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/26616 Implement C++17 std::string_view for C++11. This is useful for compile time type name retrievaly which I'm going to stack on top of this. It is also useful to replace `const std::string&` with throughout our codebase. ghstack-source-id: 92100314 Test Plan: unit tests Differential Revision: D17518992 fbshipit-source-id: 48e31c677d51b0041f4b37e89a92bd176d4a0b08
This commit is contained in:
parent
9ea42f8d7c
commit
70e9ef518f
|
|
@ -263,4 +263,13 @@ constexpr uint32_t CUDA_THREADS_PER_BLOCK_FALLBACK = 256;
|
|||
#define C10_CPP14_HOST_CONSTEXPR AT_CPP14_CONSTEXPR
|
||||
#endif
|
||||
|
||||
#if !defined(__clang__) && !defined(_MSC_VER) && defined(__GNUC__) && \
|
||||
__GNUC__ < 6
|
||||
#define CONSTEXPR_EXCEPT_GCC5
|
||||
#define IS_NOT_GCC5_CONSTEXPR 0
|
||||
#else
|
||||
#define CONSTEXPR_EXCEPT_GCC5 AT_CPP14_CONSTEXPR
|
||||
#define IS_NOT_GCC5_CONSTEXPR AT_IS_CPP14_CONSTEXPR
|
||||
#endif
|
||||
|
||||
#endif // C10_MACROS_MACROS_H_
|
||||
|
|
|
|||
14
c10/test/util/C++17_test.cpp
Normal file
14
c10/test/util/C++17_test.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include <c10/util/C++17.h>
|
||||
|
||||
using c10::guts::max;
|
||||
using c10::guts::min;
|
||||
|
||||
static_assert(min(3, 5) == 3, "");
|
||||
static_assert(min(5, 3) == 3, "");
|
||||
static_assert(min(3, 3) == 3, "");
|
||||
static_assert(min(3.0, 3.1) == 3.0, "");
|
||||
|
||||
static_assert(max(3, 5) == 5, "");
|
||||
static_assert(max(5, 3) == 5, "");
|
||||
static_assert(max(3, 3) == 3, "");
|
||||
static_assert(max(3.0, 3.1) == 3.1, "");
|
||||
1685
c10/test/util/string_view_test.cpp
Normal file
1685
c10/test/util/string_view_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -294,6 +294,15 @@ template<class T> inline std::string to_string(T value) {
|
|||
return detail::to_string_<T>::call(value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr const T& min(const T& a, const T& b) {
|
||||
return (b < a) ? b : a;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr const T& max(const T& a, const T& b) {
|
||||
return (a < b) ? b : a;
|
||||
}
|
||||
}}
|
||||
|
||||
#endif // C10_UTIL_CPP17_H_
|
||||
|
|
|
|||
295
c10/util/reverse_iterator.h
Normal file
295
c10/util/reverse_iterator.h
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* A constexpr std::reverse_iterator for C++11.
|
||||
* Implementation taken from libstdc++,
|
||||
* https://raw.githubusercontent.com/gcc-mirror/gcc/gcc-9_2_0-release/libstdc%2B%2B-v3/include/bits/stl_iterator.h
|
||||
* adapted to our code base and constexpr'ified.
|
||||
*/
|
||||
|
||||
// Copyright (C) 2001-2019 Free Software Foundation, Inc.
|
||||
//
|
||||
// This file is part of the GNU ISO C++ Library. This library is free
|
||||
// software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the
|
||||
// Free Software Foundation; either version 3, or (at your option)
|
||||
// any later version.
|
||||
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// Under Section 7 of GPL version 3, you are granted additional
|
||||
// permissions described in the GCC Runtime Library Exception, version
|
||||
// 3.1, as published by the Free Software Foundation.
|
||||
|
||||
// You should have received a copy of the GNU General Public License and
|
||||
// a copy of the GCC Runtime Library Exception along with this program;
|
||||
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1994
|
||||
* Hewlett-Packard Company
|
||||
*
|
||||
* Permission to use, copy, modify, distribute and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appear in all copies and
|
||||
* that both that copyright notice and this permission notice appear
|
||||
* in supporting documentation. Hewlett-Packard Company makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1996-1998
|
||||
* Silicon Graphics Computer Systems, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appear in all copies and
|
||||
* that both that copyright notice and this permission notice appear
|
||||
* in supporting documentation. Silicon Graphics makes no
|
||||
* representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*/
|
||||
|
||||
#include <c10/util/C++17.h>
|
||||
#include <iterator>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
template <typename _Iterator>
|
||||
class reverse_iterator
|
||||
: public std::iterator<
|
||||
typename std::iterator_traits<_Iterator>::iterator_category,
|
||||
typename std::iterator_traits<_Iterator>::value_type,
|
||||
typename std::iterator_traits<_Iterator>::difference_type,
|
||||
typename std::iterator_traits<_Iterator>::pointer,
|
||||
typename std::iterator_traits<_Iterator>::reference> {
|
||||
protected:
|
||||
_Iterator current;
|
||||
|
||||
using __traits_type = std::iterator_traits<_Iterator>;
|
||||
|
||||
public:
|
||||
using iterator_type = _Iterator;
|
||||
using difference_type = typename __traits_type::difference_type;
|
||||
using pointer = typename __traits_type::pointer;
|
||||
using reference = typename __traits_type::reference;
|
||||
|
||||
constexpr reverse_iterator() : current() {}
|
||||
|
||||
explicit constexpr reverse_iterator(iterator_type __x) : current(__x) {}
|
||||
|
||||
constexpr reverse_iterator(const reverse_iterator& __x)
|
||||
: current(__x.current) {}
|
||||
|
||||
AT_CPP14_CONSTEXPR reverse_iterator& operator=(
|
||||
const reverse_iterator& rhs) noexcept {
|
||||
current = rhs.current;
|
||||
}
|
||||
|
||||
template <typename _Iter>
|
||||
constexpr reverse_iterator(const reverse_iterator<_Iter>& __x)
|
||||
: current(__x.base()) {}
|
||||
|
||||
constexpr iterator_type base() const {
|
||||
return current;
|
||||
}
|
||||
|
||||
constexpr reference operator*() const {
|
||||
#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
|
||||
_Iterator iter = current;
|
||||
return *--iter;
|
||||
#else
|
||||
// Only works for random access iterators if we're not C++14 :(
|
||||
return *(current - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const {
|
||||
#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
|
||||
_Iterator iter = current;
|
||||
return _S_to_pointer(--iter);
|
||||
#else
|
||||
// Only works for random access iterators if we're not C++14 :(
|
||||
return _S_to_pointer(current - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
AT_CPP14_CONSTEXPR reverse_iterator& operator++() {
|
||||
--current;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AT_CPP14_CONSTEXPR reverse_iterator operator++(int) {
|
||||
reverse_iterator __tmp = *this;
|
||||
--current;
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
AT_CPP14_CONSTEXPR reverse_iterator& operator--() {
|
||||
++current;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AT_CPP14_CONSTEXPR reverse_iterator operator--(int) {
|
||||
reverse_iterator __tmp = *this;
|
||||
++current;
|
||||
return __tmp;
|
||||
}
|
||||
|
||||
constexpr reverse_iterator operator+(difference_type __n) const {
|
||||
return reverse_iterator(current - __n);
|
||||
}
|
||||
|
||||
AT_CPP14_CONSTEXPR reverse_iterator& operator+=(difference_type __n) {
|
||||
current -= __n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr reverse_iterator operator-(difference_type __n) const {
|
||||
return reverse_iterator(current + __n);
|
||||
}
|
||||
|
||||
AT_CPP14_CONSTEXPR reverse_iterator& operator-=(difference_type __n) {
|
||||
current += __n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr reference operator[](difference_type __n) const {
|
||||
return *(*this + __n);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename _Tp>
|
||||
static constexpr _Tp* _S_to_pointer(_Tp* __p) {
|
||||
return __p;
|
||||
}
|
||||
|
||||
template <typename _Tp>
|
||||
static constexpr pointer _S_to_pointer(_Tp __t) {
|
||||
return __t.operator->();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename _Iterator>
|
||||
inline constexpr bool operator==(
|
||||
const reverse_iterator<_Iterator>& __x,
|
||||
const reverse_iterator<_Iterator>& __y) {
|
||||
return __x.base() == __y.base();
|
||||
}
|
||||
|
||||
template <typename _Iterator>
|
||||
inline constexpr bool operator<(
|
||||
const reverse_iterator<_Iterator>& __x,
|
||||
const reverse_iterator<_Iterator>& __y) {
|
||||
return __y.base() < __x.base();
|
||||
}
|
||||
|
||||
template <typename _Iterator>
|
||||
inline constexpr bool operator!=(
|
||||
const reverse_iterator<_Iterator>& __x,
|
||||
const reverse_iterator<_Iterator>& __y) {
|
||||
return !(__x == __y);
|
||||
}
|
||||
|
||||
template <typename _Iterator>
|
||||
inline constexpr bool operator>(
|
||||
const reverse_iterator<_Iterator>& __x,
|
||||
const reverse_iterator<_Iterator>& __y) {
|
||||
return __y < __x;
|
||||
}
|
||||
|
||||
template <typename _Iterator>
|
||||
inline constexpr bool operator<=(
|
||||
const reverse_iterator<_Iterator>& __x,
|
||||
const reverse_iterator<_Iterator>& __y) {
|
||||
return !(__y < __x);
|
||||
}
|
||||
|
||||
template <typename _Iterator>
|
||||
inline constexpr bool operator>=(
|
||||
const reverse_iterator<_Iterator>& __x,
|
||||
const reverse_iterator<_Iterator>& __y) {
|
||||
return !(__x < __y);
|
||||
}
|
||||
|
||||
template <typename _IteratorL, typename _IteratorR>
|
||||
inline constexpr bool operator==(
|
||||
const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y) {
|
||||
return __x.base() == __y.base();
|
||||
}
|
||||
|
||||
template <typename _IteratorL, typename _IteratorR>
|
||||
inline constexpr bool operator<(
|
||||
const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y) {
|
||||
return __y.base() < __x.base();
|
||||
}
|
||||
|
||||
template <typename _IteratorL, typename _IteratorR>
|
||||
inline constexpr bool operator!=(
|
||||
const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y) {
|
||||
return !(__x == __y);
|
||||
}
|
||||
|
||||
template <typename _IteratorL, typename _IteratorR>
|
||||
inline constexpr bool operator>(
|
||||
const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y) {
|
||||
return __y < __x;
|
||||
}
|
||||
|
||||
template <typename _IteratorL, typename _IteratorR>
|
||||
inline constexpr bool operator<=(
|
||||
const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y) {
|
||||
return !(__y < __x);
|
||||
}
|
||||
|
||||
template <typename _IteratorL, typename _IteratorR>
|
||||
inline constexpr bool operator>=(
|
||||
const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y) {
|
||||
return !(__x < __y);
|
||||
}
|
||||
|
||||
template <typename _IteratorL, typename _IteratorR>
|
||||
inline constexpr auto operator-(
|
||||
const reverse_iterator<_IteratorL>& __x,
|
||||
const reverse_iterator<_IteratorR>& __y)
|
||||
-> decltype(__y.base() - __x.base()) {
|
||||
return __y.base() - __x.base();
|
||||
}
|
||||
|
||||
template <typename _Iterator>
|
||||
inline constexpr reverse_iterator<_Iterator> operator+(
|
||||
typename reverse_iterator<_Iterator>::difference_type __n,
|
||||
const reverse_iterator<_Iterator>& __x) {
|
||||
return reverse_iterator<_Iterator>(__x.base() - __n);
|
||||
}
|
||||
|
||||
template <typename _Iterator>
|
||||
inline constexpr reverse_iterator<_Iterator> __make_reverse_iterator(
|
||||
_Iterator __i) {
|
||||
return reverse_iterator<_Iterator>(__i);
|
||||
}
|
||||
|
||||
template <typename _Iterator>
|
||||
inline constexpr reverse_iterator<_Iterator> make_reverse_iterator(
|
||||
_Iterator __i) {
|
||||
return reverse_iterator<_Iterator>(__i);
|
||||
}
|
||||
|
||||
template <typename _Iterator>
|
||||
auto __niter_base(reverse_iterator<_Iterator> __it)
|
||||
-> decltype(__make_reverse_iterator(__niter_base(__it.base()))) {
|
||||
return __make_reverse_iterator(__niter_base(__it.base()));
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
677
c10/util/string_view.h
Normal file
677
c10/util/string_view.h
Normal file
|
|
@ -0,0 +1,677 @@
|
|||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/C++17.h>
|
||||
#include <c10/util/reverse_iterator.h>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* Reimplementation of std::string_view for C++11.
|
||||
* Implemented following the interface definition in
|
||||
* https://en.cppreference.com/w/cpp/string/basic_string_view
|
||||
* See there for the API documentation.
|
||||
*
|
||||
* Difference: We don't have a Traits template parameter because
|
||||
* std::char_traits isn't constexpr and we'd have to reimplement
|
||||
* std::char_traits if we wanted to use it with our constexpr basic_string_view.
|
||||
*/
|
||||
template <class CharT>
|
||||
class basic_string_view final {
|
||||
public:
|
||||
using value_type = CharT;
|
||||
using pointer = CharT*;
|
||||
using const_pointer = const CharT*;
|
||||
using reference = CharT&;
|
||||
using const_reference = const CharT&;
|
||||
using const_iterator = const CharT*;
|
||||
using iterator = const_iterator;
|
||||
using const_reverse_iterator = c10::reverse_iterator<const_iterator>;
|
||||
using reverse_iterator = const_reverse_iterator;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
static constexpr size_type npos = size_type(-1);
|
||||
|
||||
constexpr basic_string_view() noexcept : begin_(nullptr), size_(0) {}
|
||||
|
||||
explicit constexpr basic_string_view(const_pointer str, size_type count)
|
||||
: begin_(str), size_(count) {}
|
||||
|
||||
/* implicit */ constexpr basic_string_view(const_pointer str)
|
||||
: basic_string_view(str, strlen_(str)) {}
|
||||
|
||||
/* implicit */ basic_string_view(const ::std::basic_string<CharT>& str)
|
||||
: basic_string_view(str.data(), str.size()) {}
|
||||
|
||||
constexpr basic_string_view(const basic_string_view&) noexcept = default;
|
||||
|
||||
AT_CPP14_CONSTEXPR basic_string_view& operator=(
|
||||
const basic_string_view& rhs) noexcept {
|
||||
begin_ = rhs.begin_;
|
||||
size_ = rhs.size_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator ::std::basic_string<CharT>() const {
|
||||
return ::std::basic_string<CharT>(data(), size());
|
||||
}
|
||||
|
||||
constexpr const_iterator begin() const noexcept {
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
constexpr const_iterator cbegin() const noexcept {
|
||||
return begin_;
|
||||
}
|
||||
|
||||
constexpr const_iterator end() const noexcept {
|
||||
return cend();
|
||||
}
|
||||
|
||||
constexpr const_iterator cend() const noexcept {
|
||||
return begin_ + size_;
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rbegin() const noexcept {
|
||||
return crbegin();
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crbegin() const noexcept {
|
||||
return const_reverse_iterator(this->end());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator rend() const noexcept {
|
||||
return crend();
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crend() const noexcept {
|
||||
return const_reverse_iterator(this->begin());
|
||||
}
|
||||
|
||||
friend constexpr const_iterator begin(basic_string_view sv) noexcept {
|
||||
return sv.begin();
|
||||
}
|
||||
|
||||
friend constexpr const_iterator end(basic_string_view sv) noexcept {
|
||||
return sv.end();
|
||||
}
|
||||
|
||||
constexpr const_reference operator[](size_type pos) const {
|
||||
return at(pos);
|
||||
}
|
||||
|
||||
constexpr const_reference at(size_type pos) const {
|
||||
#if !defined( \
|
||||
__CUDA_ARCH__) // CUDA doesn't like std::out_of_range in device code
|
||||
return C10_UNLIKELY(pos >= size_)
|
||||
? (throw std::out_of_range(
|
||||
"string_view::operator[] or string_view::at() out of range. Index: " +
|
||||
std::to_string(pos) + ", size: " + std::to_string(size())),
|
||||
at_(0))
|
||||
: at_(pos);
|
||||
#else
|
||||
return at_(pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr const_reference front() const {
|
||||
return *begin_;
|
||||
}
|
||||
|
||||
constexpr const_reference back() const {
|
||||
return *(begin_ + size_ - 1);
|
||||
}
|
||||
|
||||
constexpr const_pointer data() const noexcept {
|
||||
return begin_;
|
||||
}
|
||||
|
||||
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<difference_type>::max();
|
||||
}
|
||||
|
||||
C10_NODISCARD constexpr bool empty() const noexcept {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
CONSTEXPR_EXCEPT_GCC5 void remove_prefix(size_type n) {
|
||||
if (n > size()) {
|
||||
throw std::out_of_range(
|
||||
"basic_string_view::remove_prefix: out of range. PrefixLength: " +
|
||||
c10::guts::to_string(n) + ", size: " + c10::guts::to_string(size()));
|
||||
}
|
||||
begin_ += n;
|
||||
size_ -= n;
|
||||
}
|
||||
|
||||
CONSTEXPR_EXCEPT_GCC5 void remove_suffix(size_type n) {
|
||||
if (n > size()) {
|
||||
throw std::out_of_range(
|
||||
"basic_string_view::remove_suffix: out of range. SuffixLength: " +
|
||||
c10::guts::to_string(n) + ", size: " + c10::guts::to_string(size()));
|
||||
}
|
||||
size_ -= n;
|
||||
}
|
||||
|
||||
CONSTEXPR_EXCEPT_GCC5 void swap(basic_string_view& sv) noexcept {
|
||||
auto tmp = *this;
|
||||
*this = sv;
|
||||
sv = tmp;
|
||||
}
|
||||
|
||||
size_type copy(pointer dest, size_type count, size_type pos = 0) const {
|
||||
if (pos > size_) {
|
||||
throw std::out_of_range(
|
||||
"basic_string_view::copy: out of range. Index: " +
|
||||
c10::guts::to_string(pos) +
|
||||
", size: " + c10::guts::to_string(size()));
|
||||
}
|
||||
size_type copy_length = c10::guts::min(count, size_ - pos);
|
||||
for (auto iter = begin() + pos, end = iter + copy_length; iter != end;) {
|
||||
*(dest++) = *(iter++);
|
||||
}
|
||||
return copy_length;
|
||||
}
|
||||
|
||||
constexpr basic_string_view substr(size_type pos = 0, size_type count = npos)
|
||||
const {
|
||||
#if !defined( \
|
||||
__CUDA_ARCH__) // CUDA doesn't like std::out_of_range in device code
|
||||
return (pos > size_)
|
||||
? (throw std::out_of_range(
|
||||
"basic_string_view::substr parameter out of bounds. Index: " +
|
||||
std::to_string(pos) + ", size: " + std::to_string(size())),
|
||||
substr_())
|
||||
: substr_(pos, count);
|
||||
#else
|
||||
return substr_(pos, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr int compare(basic_string_view rhs) const noexcept {
|
||||
#if __cpp_constexpr >= 201304
|
||||
// if we are in C++14, write it iteratively. This is faster.
|
||||
for (size_t i = 0, end = c10::guts::min(size(), rhs.size()); i < end; ++i) {
|
||||
if (at_(i) < rhs.at_(i)) {
|
||||
return -1;
|
||||
} else if (at_(i) > rhs.at_(i)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (size() < rhs.size()) {
|
||||
return -1;
|
||||
} else if (size() > rhs.size()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
// if we are in C++11, we need to do it recursively because of constexpr
|
||||
// restrictions.
|
||||
return (size() == 0 && rhs.size() == 0) ? 0
|
||||
: (size() == 0) ? -1
|
||||
: (rhs.size() == 0)
|
||||
? 1
|
||||
: (front() < rhs.front()) ? -1
|
||||
: (front() > rhs.front())
|
||||
? 1
|
||||
: substr_(1).compare(rhs.substr_(1));
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr int compare(size_type pos1, size_type count1, basic_string_view v)
|
||||
const {
|
||||
return substr(pos1, count1).compare(v);
|
||||
}
|
||||
|
||||
constexpr int compare(
|
||||
size_type pos1,
|
||||
size_type count1,
|
||||
basic_string_view v,
|
||||
size_type pos2,
|
||||
size_type count2) const {
|
||||
return substr(pos1, count1).compare(v.substr(pos2, count2));
|
||||
}
|
||||
|
||||
constexpr int compare(const_pointer s) const {
|
||||
return compare(basic_string_view(s));
|
||||
}
|
||||
|
||||
constexpr int compare(size_type pos1, size_type count1, const_pointer s)
|
||||
const {
|
||||
return substr(pos1, count1).compare(basic_string_view(s));
|
||||
}
|
||||
|
||||
constexpr int compare(
|
||||
size_type pos1,
|
||||
size_type count1,
|
||||
const_pointer s,
|
||||
size_type count2) const {
|
||||
return substr(pos1, count1).compare(basic_string_view(s, count2));
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(
|
||||
basic_string_view lhs,
|
||||
basic_string_view rhs) noexcept {
|
||||
return lhs.equals_(rhs);
|
||||
}
|
||||
|
||||
friend constexpr bool operator!=(
|
||||
basic_string_view lhs,
|
||||
basic_string_view rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
friend constexpr bool operator<(
|
||||
basic_string_view lhs,
|
||||
basic_string_view rhs) noexcept {
|
||||
return lhs.compare(rhs) < 0;
|
||||
}
|
||||
|
||||
friend constexpr bool operator>=(
|
||||
basic_string_view lhs,
|
||||
basic_string_view rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
friend constexpr bool operator>(
|
||||
basic_string_view lhs,
|
||||
basic_string_view rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
friend constexpr bool operator<=(
|
||||
basic_string_view lhs,
|
||||
basic_string_view rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
constexpr bool starts_with(basic_string_view prefix) const noexcept {
|
||||
return (prefix.size() > size()) ? false
|
||||
: prefix.equals_(substr_(0, prefix.size()));
|
||||
}
|
||||
|
||||
constexpr bool starts_with(CharT prefix) const noexcept {
|
||||
return !empty() && prefix == front();
|
||||
}
|
||||
|
||||
constexpr bool starts_with(const_pointer prefix) const {
|
||||
return starts_with(basic_string_view(prefix));
|
||||
}
|
||||
|
||||
constexpr bool ends_with(basic_string_view suffix) const noexcept {
|
||||
return (suffix.size() > size())
|
||||
? false
|
||||
: suffix.equals_(substr_(size() - suffix.size(), suffix.size()));
|
||||
}
|
||||
|
||||
constexpr bool ends_with(CharT suffix) const noexcept {
|
||||
return !empty() && suffix == back();
|
||||
}
|
||||
|
||||
constexpr bool ends_with(const_pointer suffix) const {
|
||||
return ends_with(basic_string_view(suffix));
|
||||
}
|
||||
|
||||
constexpr size_type find(basic_string_view v, size_type pos = 0) const
|
||||
noexcept {
|
||||
#if __cpp_constexpr >= 201304
|
||||
// if we are in C++14, write it iteratively. This is faster.
|
||||
if (v.size() == 0) {
|
||||
return pos <= size() ? pos : npos;
|
||||
}
|
||||
|
||||
if (pos + v.size() <= size()) {
|
||||
for (size_type cur = pos, end = size() - v.size(); cur <= end; ++cur) {
|
||||
if (v.at_(0) == at_(cur) &&
|
||||
v.substr_(1).equals_(substr_(cur + 1, v.size() - 1))) {
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
#else
|
||||
// if we are in C++11, we need to do it recursively because of constexpr
|
||||
// restrictions.
|
||||
return (v.size() == 0) ? (pos <= size() ? pos : npos)
|
||||
: (pos + v.size() > size())
|
||||
? npos
|
||||
: (v.at_(0) == at_(pos) &&
|
||||
v.substr_(1).equals_(substr_(pos + 1, v.size() - 1)))
|
||||
? pos
|
||||
: find(v, pos + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr size_type find(CharT ch, size_type pos = 0) const noexcept {
|
||||
return find_first_if_(pos, charIsEqual_{ch});
|
||||
}
|
||||
|
||||
constexpr size_type find(const_pointer s, size_type pos, size_type count)
|
||||
const {
|
||||
return find(basic_string_view(s, count), pos);
|
||||
}
|
||||
|
||||
constexpr size_type find(const_pointer s, size_type pos = 0) const {
|
||||
return find(basic_string_view(s), pos);
|
||||
}
|
||||
|
||||
constexpr size_type rfind(basic_string_view v, size_type pos = npos) const
|
||||
noexcept {
|
||||
#if __cpp_constexpr >= 201304
|
||||
// if we are in C++14, write it iteratively. This is faster.
|
||||
if (v.size() == 0) {
|
||||
return pos <= size() ? pos : size();
|
||||
}
|
||||
|
||||
if (v.size() <= size()) {
|
||||
pos = c10::guts::min(size() - v.size(), pos);
|
||||
do {
|
||||
if (v.at_(0) == at_(pos) &&
|
||||
v.substr_(1).equals_(substr_(pos + 1, v.size() - 1))) {
|
||||
return pos;
|
||||
}
|
||||
} while (pos-- > 0);
|
||||
}
|
||||
return npos;
|
||||
#else
|
||||
// if we are in C++11, we need to do it recursively because of constexpr
|
||||
// restrictions.
|
||||
return (v.size() == 0) ? (pos <= size() ? pos : size())
|
||||
: (v.size() > size()) ? npos
|
||||
: (size() - v.size() < pos)
|
||||
? rfind(v, size() - v.size())
|
||||
: (v.at_(0) == at_(pos) &&
|
||||
v.substr_(1).equals_(substr_(pos + 1, v.size() - 1)))
|
||||
? pos
|
||||
: (pos == 0) ? npos : rfind(v, pos - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr size_type rfind(CharT ch, size_type pos = npos) const noexcept {
|
||||
return find_last_if_(pos, charIsEqual_{ch});
|
||||
}
|
||||
|
||||
constexpr size_type rfind(const_pointer s, size_type pos, size_type count)
|
||||
const {
|
||||
return rfind(basic_string_view(s, count), pos);
|
||||
}
|
||||
|
||||
constexpr size_type rfind(const_pointer s, size_type pos = npos) const {
|
||||
return rfind(basic_string_view(s), pos);
|
||||
}
|
||||
|
||||
constexpr size_type find_first_of(basic_string_view v, size_type pos = 0)
|
||||
const noexcept {
|
||||
return find_first_if_(pos, stringViewContainsChar_{v});
|
||||
}
|
||||
|
||||
constexpr size_type find_first_of(CharT ch, size_type pos = 0) const
|
||||
noexcept {
|
||||
return find_first_if_(pos, charIsEqual_{ch});
|
||||
}
|
||||
|
||||
constexpr size_type find_first_of(
|
||||
const_pointer s,
|
||||
size_type pos,
|
||||
size_type count) const {
|
||||
return find_first_of(basic_string_view(s, count), pos);
|
||||
}
|
||||
|
||||
constexpr size_type find_first_of(const_pointer s, size_type pos = 0) const {
|
||||
return find_first_of(basic_string_view(s), pos);
|
||||
}
|
||||
|
||||
constexpr size_type find_last_of(basic_string_view v, size_type pos = npos)
|
||||
const noexcept {
|
||||
return find_last_if_(pos, stringViewContainsChar_{v});
|
||||
}
|
||||
|
||||
constexpr size_type find_last_of(CharT ch, size_type pos = npos) const
|
||||
noexcept {
|
||||
return find_last_if_(pos, charIsEqual_{ch});
|
||||
}
|
||||
|
||||
constexpr size_type find_last_of(
|
||||
const_pointer s,
|
||||
size_type pos,
|
||||
size_type count) const {
|
||||
return find_last_of(basic_string_view(s, count), pos);
|
||||
}
|
||||
|
||||
constexpr size_type find_last_of(const_pointer s, size_type pos = npos)
|
||||
const {
|
||||
return find_last_of(basic_string_view(s), pos);
|
||||
}
|
||||
|
||||
constexpr size_type find_first_not_of(basic_string_view v, size_type pos = 0)
|
||||
const noexcept {
|
||||
return find_first_if_(pos, stringViewDoesNotContainChar_{v});
|
||||
}
|
||||
|
||||
constexpr size_type find_first_not_of(CharT ch, size_type pos = 0) const
|
||||
noexcept {
|
||||
return find_first_if_(pos, charIsNotEqual_{ch});
|
||||
}
|
||||
|
||||
constexpr size_type find_first_not_of(
|
||||
const_pointer s,
|
||||
size_type pos,
|
||||
size_type count) const {
|
||||
return find_first_not_of(basic_string_view(s, count), pos);
|
||||
}
|
||||
|
||||
constexpr size_type find_first_not_of(const_pointer s, size_type pos = 0)
|
||||
const {
|
||||
return find_first_not_of(basic_string_view(s), pos);
|
||||
}
|
||||
|
||||
constexpr size_type find_last_not_of(
|
||||
basic_string_view v,
|
||||
size_type pos = npos) const noexcept {
|
||||
return find_last_if_(pos, stringViewDoesNotContainChar_{v});
|
||||
}
|
||||
|
||||
constexpr size_type find_last_not_of(CharT ch, size_type pos = npos) const
|
||||
noexcept {
|
||||
return find_last_if_(pos, charIsNotEqual_{ch});
|
||||
}
|
||||
|
||||
constexpr size_type find_last_not_of(
|
||||
const_pointer s,
|
||||
size_type pos,
|
||||
size_type count) const {
|
||||
return find_last_not_of(basic_string_view(s, count), pos);
|
||||
}
|
||||
|
||||
constexpr size_type find_last_not_of(const_pointer s, size_type pos = npos)
|
||||
const {
|
||||
return find_last_not_of(basic_string_view(s), pos);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_type strlen_(const_pointer str) noexcept {
|
||||
#if __cpp_constexpr >= 201304
|
||||
// if we are in C++14, write it iteratively. This is faster.
|
||||
const_pointer current = str;
|
||||
while (*current != '\0') {
|
||||
++current;
|
||||
}
|
||||
return current - str;
|
||||
#else
|
||||
// if we are in C++11, we need to do it recursively because of constexpr
|
||||
// restrictions.
|
||||
return (*str == '\0') ? 0 : 1 + strlen_(str + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr const_reference at_(size_type pos) const noexcept {
|
||||
return *(begin_ + pos);
|
||||
}
|
||||
|
||||
constexpr basic_string_view substr_(size_type pos = 0, size_type count = npos)
|
||||
const {
|
||||
return basic_string_view{begin_ + pos, c10::guts::min(count, size() - pos)};
|
||||
}
|
||||
|
||||
template <class Condition>
|
||||
constexpr size_type find_first_if_(size_type pos, Condition&& condition) const
|
||||
noexcept {
|
||||
#if __cpp_constexpr >= 201304
|
||||
// if we are in C++14, write it iteratively. This is faster.
|
||||
if (pos + 1 <= size()) {
|
||||
for (size_type cur = pos; cur < size(); ++cur) {
|
||||
if (condition(at_(cur))) {
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
return npos;
|
||||
#else
|
||||
// if we are in C++11, we need to do it recursively because of constexpr
|
||||
// restrictions.
|
||||
return (pos + 1 > size()) ? npos
|
||||
: condition(at_(pos))
|
||||
? pos
|
||||
: find_first_if_(pos + 1, std::forward<Condition>(condition));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Condition>
|
||||
constexpr size_type find_last_if_(size_type pos, Condition&& condition) const
|
||||
noexcept {
|
||||
#if __cpp_constexpr >= 201304
|
||||
// if we are in C++14, write it iteratively. This is faster.
|
||||
if (size() > 0) {
|
||||
pos = c10::guts::min(size() - 1, pos);
|
||||
do {
|
||||
if (condition(at_(pos))) {
|
||||
return pos;
|
||||
}
|
||||
} while (pos-- > 0);
|
||||
}
|
||||
return npos;
|
||||
#else
|
||||
// if we are in C++11, we need to do it recursively because of constexpr
|
||||
// restrictions.
|
||||
return (size() == 0) ? npos
|
||||
: (pos >= size())
|
||||
? find_last_if_(size() - 1, std::forward<Condition>(condition))
|
||||
: condition(at_(pos))
|
||||
? pos
|
||||
: (pos == 0) ? npos
|
||||
: find_last_if_(
|
||||
pos - 1, std::forward<Condition>(condition));
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr bool equals_(basic_string_view rhs) const {
|
||||
// We don't use string_view::compare() here but implement it manually because
|
||||
// only looking at equality allows for more optimized code.
|
||||
#if __cpp_constexpr >= 201304
|
||||
// if we are in C++14, write it iteratively. This is faster.
|
||||
if (size() != rhs.size()) {
|
||||
return false;
|
||||
}
|
||||
// Yes, memcmp would be laster than this loop, but memcmp isn't constexpr
|
||||
// and I didn't feel like implementing a constexpr memcmp variant.
|
||||
// TODO At some point this should probably be done, including tricks
|
||||
// like comparing one machine word instead of a byte per iteration.
|
||||
for (typename basic_string_view<CharT>::size_type pos = 0; pos < size();
|
||||
++pos) {
|
||||
if (at_(pos) != rhs.at_(pos)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
// if we are in C++11, we need to do it recursively because of constexpr
|
||||
// restrictions.
|
||||
return (size() != rhs.size()) ? false
|
||||
: (size() == 0)
|
||||
? true
|
||||
: (front() != rhs.front()) ? false
|
||||
: (substr_(1).equals_(rhs.substr_(1)));
|
||||
#endif
|
||||
}
|
||||
|
||||
struct charIsEqual_ final {
|
||||
CharT expected;
|
||||
constexpr bool operator()(CharT actual) const noexcept {
|
||||
return expected == actual;
|
||||
}
|
||||
};
|
||||
|
||||
struct charIsNotEqual_ final {
|
||||
CharT expected;
|
||||
constexpr bool operator()(CharT actual) const noexcept {
|
||||
return expected != actual;
|
||||
}
|
||||
};
|
||||
|
||||
struct stringViewContainsChar_ final {
|
||||
basic_string_view expected;
|
||||
constexpr bool operator()(CharT ch) const noexcept {
|
||||
return npos != expected.find(ch);
|
||||
}
|
||||
};
|
||||
|
||||
struct stringViewDoesNotContainChar_ final {
|
||||
basic_string_view expected;
|
||||
constexpr bool operator()(CharT ch) const noexcept {
|
||||
return npos == expected.find(ch);
|
||||
}
|
||||
};
|
||||
|
||||
const_pointer begin_;
|
||||
size_type size_;
|
||||
};
|
||||
|
||||
template <class CharT>
|
||||
inline std::basic_ostream<CharT>& operator<<(
|
||||
std::basic_ostream<CharT>& stream,
|
||||
basic_string_view<CharT> sv) {
|
||||
// The rules for operator<< are quite complex, but std::string has the same.
|
||||
// Let's just rely on the std::string implementation. This might be a bit
|
||||
// slower, but I don't think performance matters here.
|
||||
return stream << ::std::basic_string<CharT>(sv);
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
CONSTEXPR_EXCEPT_GCC5 inline void swap(
|
||||
basic_string_view<CharT>& lhs,
|
||||
basic_string_view<CharT>& rhs) {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
using string_view = basic_string_view<char>;
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace std {
|
||||
template <class CharT>
|
||||
struct hash<::c10::basic_string_view<CharT>> {
|
||||
size_t operator()(::c10::basic_string_view<CharT> x) const {
|
||||
// The standard says that std""string_view hashing must do the same as
|
||||
// std::string hashing but leaves the details of std::string hashing
|
||||
// up to the implementer. So, to be conformant, we need to have the same
|
||||
// behavior as the implementer-defined std::string hasher of the STL
|
||||
// we're built against. Let's just call it. This is probably slow
|
||||
// but the only way to be conformant.
|
||||
return std::hash<::std::basic_string<CharT>>()(
|
||||
::std::basic_string<CharT>(x));
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
Loading…
Reference in New Issue
Block a user