290 lines
8.8 KiB
C++
290 lines
8.8 KiB
C++
/*
|
|
Copyright (C) 2016 by Statoil ASA
|
|
|
|
This file is part of the Open Porous Media project (OPM).
|
|
|
|
OPM 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 of the License, or
|
|
(at your option) any later version.
|
|
|
|
OPM 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.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef OPM_UTILITY_SUBSTRING_HPP
|
|
#define OPM_UTILITY_SUBSTRING_HPP
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
#include <iosfwd>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
namespace Opm {
|
|
/*
|
|
* string_view is a simple view-into-substring feature whose primary
|
|
* usecase is to avoid deep copying strings in the inner loops of the
|
|
* parser. Relies on whatever it's viewing into is kept alive (as all
|
|
* iterators do):
|
|
*
|
|
* auto rec = make_raw_record();
|
|
* string_view view = rec.getItem( 3 );
|
|
*
|
|
* view.size(); view[ 10 ]; // ok
|
|
* ~rec();
|
|
* view[ 3 ]; // not ok
|
|
*
|
|
* This is desired to fill out a gap in the C++ standard library, since
|
|
* string_view has yet to be standardised
|
|
*
|
|
* http://en.cppreference.com/w/cpp/experimental/basic_string_view
|
|
*/
|
|
class string_view {
|
|
public:
|
|
using const_iterator = const char*;
|
|
|
|
inline string_view() = default;
|
|
inline string_view( const_iterator, const_iterator );
|
|
inline string_view( const_iterator, size_t );
|
|
//cppcheck-suppress noExplicitConstructor
|
|
inline string_view( const std::string& );
|
|
inline string_view( const std::string&, size_t );
|
|
//cppcheck-suppress noExplicitConstructor
|
|
inline string_view( const char* );
|
|
|
|
inline const_iterator begin() const;
|
|
inline const_iterator end() const;
|
|
|
|
inline char front() const;
|
|
inline char back() const;
|
|
|
|
inline char operator[]( size_t ) const;
|
|
inline bool operator<( const string_view& ) const;
|
|
inline bool operator==( const string_view& ) const;
|
|
|
|
inline bool empty() const;
|
|
inline size_t size() const;
|
|
inline size_t length() const;
|
|
|
|
inline std::string string() const;
|
|
inline std::string substr( size_t from = 0 ) const;
|
|
inline std::string substr( size_t from, size_t len ) const;
|
|
|
|
inline bool starts_with(const std::string& str) const;
|
|
inline std::size_t find(const std::string& substring) const;
|
|
inline std::size_t find(char c) const;
|
|
private:
|
|
const_iterator fst = nullptr;
|
|
const_iterator lst = nullptr;
|
|
};
|
|
|
|
/*
|
|
* The implementation of string_view is inline and therefore the definitions
|
|
* are also in this file. The reason for this is performance; string_view's
|
|
* logic is trivial and function call and indirection overhead is significant
|
|
* compared to the useful work it does. Additionally, string_view is a *very*
|
|
* much used class in the inner loops of the parser - inlining the
|
|
* implementation measured to improve performance by some 10%.
|
|
*/
|
|
|
|
|
|
// Non-member operators using string_view.
|
|
|
|
std::ostream& operator<<( std::ostream& stream, const Opm::string_view& view );
|
|
|
|
inline std::string operator+( std::string str, const Opm::string_view& view ) {
|
|
return str.append( view.begin(), view.end() );
|
|
}
|
|
|
|
inline std::string operator+( const Opm::string_view& view, const std::string& str ) {
|
|
return view.string().append( str.begin(), str.end() );
|
|
}
|
|
|
|
inline bool operator==( const Opm::string_view& view, const std::string& rhs ) {
|
|
return rhs.size() == view.size() &&
|
|
std::equal( view.begin(), view.end(), std::begin( rhs ) );
|
|
}
|
|
|
|
inline bool operator==( const Opm::string_view& view, const char* rhs ) {
|
|
return std::strlen( rhs ) == view.size() &&
|
|
std::equal( view.begin(), view.end(), rhs );
|
|
}
|
|
|
|
inline bool operator==( const std::string& lhs, const Opm::string_view& view ) {
|
|
return view == lhs;
|
|
}
|
|
|
|
inline bool operator==( const char* lhs, const Opm::string_view& view ) {
|
|
return view == lhs;
|
|
}
|
|
|
|
inline bool operator!=( const Opm::string_view& view, const std::string& rhs ) {
|
|
return !( view == rhs );
|
|
}
|
|
|
|
inline bool operator!=( const std::string& lhs, const Opm::string_view& view ) {
|
|
return !( view == lhs );
|
|
}
|
|
|
|
inline bool operator!=( const Opm::string_view& view, const char* rhs ) {
|
|
return !( view == rhs );
|
|
}
|
|
|
|
inline bool operator!=( const char* lhs, const Opm::string_view& view ) {
|
|
return !( view == lhs );
|
|
}
|
|
|
|
|
|
// Member functions of string_view.
|
|
|
|
inline string_view::string_view( const_iterator first,
|
|
const_iterator last ) :
|
|
fst( first ),
|
|
lst( last )
|
|
{}
|
|
|
|
inline string_view::string_view( const_iterator first ,
|
|
size_t count ) :
|
|
fst( first ),
|
|
lst( first + count )
|
|
{}
|
|
|
|
inline string_view::string_view( const std::string& str ) :
|
|
string_view( str.data(), str.size() )
|
|
{}
|
|
|
|
inline string_view::string_view( const std::string& str, size_t count ) :
|
|
string_view( str.data(), count )
|
|
{}
|
|
|
|
inline string_view::string_view( const char* str ) :
|
|
string_view( str, str + std::strlen( str ) )
|
|
{}
|
|
|
|
inline string_view::const_iterator string_view::begin() const {
|
|
return this->fst;
|
|
}
|
|
|
|
inline string_view::const_iterator string_view::end() const {
|
|
return this->lst;
|
|
}
|
|
|
|
inline char string_view::front() const {
|
|
return *this->fst;
|
|
}
|
|
|
|
inline char string_view::back() const {
|
|
return *(this->lst - 1);
|
|
}
|
|
|
|
inline char string_view::operator[]( size_t i ) const {
|
|
return *(this->begin() + i);
|
|
}
|
|
|
|
inline bool string_view::operator<( const string_view& rhs ) const {
|
|
return std::lexicographical_compare( this->begin(), this->end(),
|
|
rhs.begin(), rhs.end() );
|
|
}
|
|
|
|
inline bool string_view::operator==( const string_view& rhs ) const {
|
|
return std::equal( this->begin(), this->end(), rhs.begin() );
|
|
}
|
|
|
|
inline bool string_view::empty() const {
|
|
return std::distance( this->begin(), this->end() ) == 0;
|
|
}
|
|
|
|
inline size_t string_view::size() const {
|
|
return std::distance( this->begin(), this->end() );
|
|
}
|
|
|
|
inline size_t string_view::length() const {
|
|
return std::distance( this->begin(), this->end() );
|
|
}
|
|
|
|
inline std::string string_view::string() const {
|
|
return this->substr();
|
|
}
|
|
|
|
inline std::string string_view::substr( size_t from ) const {
|
|
return this->substr( from, this->size() );
|
|
}
|
|
|
|
inline std::string string_view::substr( size_t from, size_t len ) const {
|
|
if( from > this->size() )
|
|
throw std::out_of_range( "'from' is greater than length" );
|
|
|
|
if (from + len > this->size())
|
|
return std::string( this->begin() + from, this->lst );
|
|
|
|
return std::string( this->begin() + from, this->begin() + len + from);
|
|
}
|
|
|
|
inline std::size_t string_view::find(const std::string& substring) const {
|
|
auto substring_size = substring.size();
|
|
if (substring_size > this->size())
|
|
return std::string::npos;
|
|
|
|
auto substring_data = substring.data();
|
|
auto pos = this->fst;
|
|
auto last_pos = this->lst - substring.size() + 1;
|
|
|
|
while (pos != last_pos) {
|
|
std::size_t si = 0;
|
|
while (substring_data[si] == *(pos + si)) {
|
|
si += 1;
|
|
if (si == substring_size)
|
|
return pos - this->fst;
|
|
}
|
|
++pos;
|
|
}
|
|
|
|
return std::string::npos;
|
|
}
|
|
|
|
inline std::size_t string_view::find(char c) const {
|
|
auto pos = this->fst;
|
|
|
|
while (pos != this->lst) {
|
|
if (*pos == c)
|
|
return pos - this->fst;
|
|
|
|
++pos;
|
|
}
|
|
|
|
return std::string::npos;
|
|
}
|
|
|
|
|
|
inline bool string_view::starts_with(const std::string& str) const {
|
|
auto str_size = str.size();
|
|
if (str_size > this->size())
|
|
return false;
|
|
|
|
auto str_data = str.data();
|
|
auto pos = this->fst;
|
|
|
|
std::size_t si = 0;
|
|
while (true) {
|
|
if (*pos != str_data[si])
|
|
return false;
|
|
|
|
++pos;
|
|
++si;
|
|
|
|
if (si == str_size)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
#endif //OPM_UTILITY_SUBSTRING_HPP
|