/*
* cpp_util_2
*/
/*!
* \since v.2.3.1
* \brief Обертка над голыми указателями на char и над std::string.
*/
#if !defined( CPP_UTIL_2__STRING_PIECE_HPP )
#define CPP_UTIL_2__STRING_PIECE_HPP
#include <string>
#include <cstring>
namespace cpp_util_2 {
//
// string_piece_t
//
/*!
* \since v.2.3.1
* \brief Обертка над голыми указателями на char и над std::string.
*
* Идея нагло сперта из библиотеки PCRE (http://www.pcre.org). Там
* этот класс используется для реалиазации C++ классов, методы которых
* должны получать строковые аргументы. Класс string_piece_t позволяет
* унифицировано работать как с const char *, так и с const std::string &
* не требуя копирования значения аргумента.
*
* \par Благодарности
* <a href="http://www.rsdn.ru/Users/48023.aspx">night beast</a> за
* обнаруженные ошибки в реализации шаблонных конструкторов.
*/
class string_piece_t
{
#if defined( CPP_UTIL_STRING_PIECE_STORE_DATA_TYPE )
public :
static const int no_type = 0;
static const int string_literal = 1;
static const int null_terminated = 2;
static const int std_basic_string = 3;
static const int array_fragment = 4;
#define CPP_UTIL_STRING_PIECE_MAKE_DATA(p, l, t) {(p), (l), (t)}
#else
#define CPP_UTIL_STRING_PIECE_MAKE_DATA(p, l, t) {(p), (l)}
#endif
private:
/*!
* \since v.2.4.0
* \brief Структура внутренностей объекта string_piece.
*/
struct data_t
{
const char * m_ptr;
size_t m_length;
#if defined(CPP_UTIL_STRING_PIECE_STORE_DATA_TYPE)
int m_type;
#endif
};
/*!
* \since v.2.4.0
* \brief Конструирование внутренностей string_piece из
* null-terminated строки.
*/
inline static data_t
from_null_terminated( const char * p )
{
data_t r = CPP_UTIL_STRING_PIECE_MAKE_DATA(
p,
p ? std::strlen( p ) : 0,
null_terminated );
return r;
}
inline static data_t
from_null_terminated( const unsigned char * p )
{
return from_null_terminated(
reinterpret_cast< const char * >( p ) );
}
/*!
* \since v.2.4.0
* \brief Конструирование внутренностей string_piece из
* строкового литерала.
*
* Особенность в том, что для "abc" параметр len будет
* равен 4, за счет терминального ноль-символа. А этот
* ноль символ в данном случае не нужен.
*/
inline static data_t
from_string_literal( const char * p, size_t len )
{
data_t r = CPP_UTIL_STRING_PIECE_MAKE_DATA(
p,
len - 1,
string_literal );
return r;
}
inline static data_t
from_string_literal( const unsigned char * p, size_t len )
{
return from_string_literal(
reinterpret_cast< const char * >( p ), len );
}
/*!
* \since v.2.4.0
* \brief Конструирование внутренностей string_piece из std::string.
*/
inline static data_t
from_std_basic_string( const std::string & s )
{
data_t r = CPP_UTIL_STRING_PIECE_MAKE_DATA(
s.data(),
s.length(),
std_basic_string );
return r;
}
/*!
* \since v.2.4.0
* \brief Конструирование внутренностей string_piece из фрагмента
* вектора char-ов.
*/
inline static data_t
from_array_fragment( const char * p, size_t len )
{
data_t r = CPP_UTIL_STRING_PIECE_MAKE_DATA(
p,
len,
array_fragment );
return r;
}
inline static data_t
from_array_fragment( const unsigned char * p, size_t len )
{
return from_array_fragment(
reinterpret_cast< const char * >( p ), len );
}
/*!
* \since v.2.4.0
* \brief Конструирование пустых внутренностей string_piece.
*/
inline static data_t
empty_data()
{
data_t r = CPP_UTIL_STRING_PIECE_MAKE_DATA( 0, 0, no_type );
return r;
}
/*!
* \since v.2.4.0
* \brief Внутренности объекта string_piece.
*/
data_t m_data;
public:
//! Конструктор по умолчанию.
string_piece_t()
: m_data( empty_data() )
{}
//! Конструктор для случая std::string.
string_piece_t( const std::string & str )
: m_data( from_std_basic_string( str ) )
{}
//! Констуктор для случая строкового буфера.
string_piece_t( const char * ptr, size_t len )
: m_data( from_array_fragment( ptr, len ) )
{}
//! Констуктор для случая строкового буфера.
string_piece_t( const unsigned char * ptr, size_t len )
: m_data( from_array_fragment( ptr, len ) )
{}
//! Конструктор для случая строкового литерала.
template< class C, size_t LEN >
string_piece_t( const C (&ptr)[ LEN ] )
: m_data( from_string_literal( ptr, LEN ) )
{}
//! Конструктор для случая null-terminated строки.
template< class C >
string_piece_t( const C * const & p )
: m_data( from_null_terminated( p ) )
{}
const char*
data() const { return m_data.m_ptr; }
size_t
size() const { return m_data.m_length; }
size_t
length() const { return m_data.m_length; }
bool
empty() const { return m_data.m_length == 0; }
#if defined( CPP_UTIL_STRING_PIECE_STORE_DATA_TYPE )
int
type() const { return m_data.m_type; }
#endif
void
clear() { m_data = empty_data(); }
void
set( const char* buffer, size_t len )
{
m_data = from_array_fragment( buffer, len );
}
void
set( const std::string & str )
{
m_data = from_std_basic_string( str );
}
template< class C, size_t LEN >
void
set( const C (&ptr)[ LEN ] )
{
m_data = from_string_literal( ptr, LEN );
}
template< class C >
void
set( const C * const & p )
{
m_data = from_null_terminated( p );
}
char
operator[](int i) const { return m_data.m_ptr[i]; }
int
compare( const string_piece_t& x ) const
{
int r = memcmp(
m_data.m_ptr,
x.m_data.m_ptr,
m_data.m_length < x.m_data.m_length ?
m_data.m_length : x.m_data.m_length );
if( r == 0 )
{
if( m_data.m_length < x.m_data.m_length ) r = -1;
else if( m_data.m_length > x.m_data.m_length ) r = +1;
}
return r;
}
bool
operator==( const string_piece_t & x ) const
{
return ( ( m_data.m_length == x.m_data.m_length ) &&
( memcmp(
m_data.m_ptr,
x.m_data.m_ptr,
m_data.m_length ) == 0 ) );
}
bool
operator!=( const string_piece_t & x ) const
{
return !(*this == x);
}
bool
operator<( const string_piece_t & x ) const
{
return compare( x ) < 0;
}
bool
operator<=( const string_piece_t & x ) const
{
return compare( x ) <= 0;
}
bool
operator>( const string_piece_t & x ) const
{
return compare( x ) > 0;
}
bool
operator>=( const string_piece_t & x ) const
{
return compare( x ) >= 0;
}
string_piece_t
substr( size_t offset, size_t len )
{
return string_piece_t( m_data.m_ptr + offset, len );
}
std::string
to_string() const
{
return std::string( data(), size() );
}
};
} /* namespace cpp_util_2 */
#endif