Introducing string_view
A simple non-mutating view into a string. Implements a shallow reference to a std::string, replicating its operations to be drop-in replaceable. Primarily designed for inner loop use, where expensive string allocations become a performance killer.
This commit is contained in:
236
opm/parser/eclipse/Utility/Stringview.hpp
Normal file
236
opm/parser/eclipse/Utility/Stringview.hpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
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 <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 = std::string::const_iterator;
|
||||
|
||||
inline string_view() = default;
|
||||
inline string_view( const std::string& );
|
||||
inline string_view( std::string::const_iterator, std::string::const_iterator );
|
||||
|
||||
inline const_iterator begin() const;
|
||||
inline const_iterator end() const;
|
||||
|
||||
inline char operator[]( size_t ) const;
|
||||
|
||||
inline size_t size() const;
|
||||
inline size_t length() const;
|
||||
|
||||
/*
|
||||
* substr operations are bounds checked, i.e. if to > from or to >
|
||||
* size then exceptions are thrown.
|
||||
*
|
||||
* returns the substring [from,to), meaning
|
||||
* view = "sample";
|
||||
* view.substr( 0, view.size() ) => sample
|
||||
* view.substr( 0, 5 ) => sampl
|
||||
*/
|
||||
inline std::string string() const;
|
||||
inline std::string substr( size_t from = 0 ) const;
|
||||
inline std::string substr( size_t from, size_t to ) const;
|
||||
|
||||
private:
|
||||
const_iterator fst;
|
||||
const_iterator lst;
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* 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%.
|
||||
*/
|
||||
|
||||
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::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 );
|
||||
}
|
||||
|
||||
|
||||
namespace boost { namespace test_tools {
|
||||
/* This is an unfortunate consequence of using boost.test.
|
||||
* For reference, see
|
||||
* http://stackoverflow.com/questions/17572583/boost-check-fails-to-compile-operator-for-custom-types
|
||||
*
|
||||
* In short, boost.test is unable to select the correct operator overloads,
|
||||
* even in the global scope, inside its test macros. As a consequence, in
|
||||
* order for boost.test to function we pry open its internals and creates a
|
||||
* specialised instantiaten of string_view, as well as custom
|
||||
* boost-namespace-specific overloads of comparison operators (that simply
|
||||
* forward to the propoer implementations.
|
||||
*/
|
||||
|
||||
template< typename T > struct print_log_value;
|
||||
|
||||
template<>
|
||||
struct print_log_value< Opm::string_view > {
|
||||
void operator()( std::ostream& os, const Opm::string_view& view ) {
|
||||
::operator<<( os, view );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
namespace tt_detail {
|
||||
|
||||
template< typename T >
|
||||
inline bool operator==( const Opm::string_view& o, const T& x ) {
|
||||
return ::operator==( o, x );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool operator==( const T& x, const Opm::string_view& o ) {
|
||||
return ::operator==( o, x );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool operator!=( const Opm::string_view& o, const T& x ) {
|
||||
return ::operator!=( o, x );
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
inline bool operator!=( const T& x, const Opm::string_view& o ) {
|
||||
return ::operator!=( o, x );
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
namespace Opm {
|
||||
inline string_view::string_view( std::string::const_iterator begin,
|
||||
std::string::const_iterator end ) :
|
||||
fst( begin ),
|
||||
lst( end )
|
||||
{}
|
||||
|
||||
inline string_view::string_view( const std::string& str ) :
|
||||
fst( str.begin() ),
|
||||
lst( str.end() )
|
||||
{}
|
||||
|
||||
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::operator[]( size_t i ) const {
|
||||
return *(this->begin() + i);
|
||||
}
|
||||
|
||||
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 to ) const {
|
||||
if( from > this->size() )
|
||||
throw std::out_of_range( "'from' is greater than length" );
|
||||
|
||||
if( to > this->size() )
|
||||
throw std::out_of_range( "'to' is greater than length" );
|
||||
|
||||
if( from > to )
|
||||
throw std::invalid_argument( "'from' is greater than 'to'" );
|
||||
|
||||
return std::string( this->begin() + from, this->begin() + to );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //OPM_UTILITY_SUBSTRING_HPP
|
||||
Reference in New Issue
Block a user