First cut of new, non-owning, StringRef class, with no dependencies in header

This commit is contained in:
Phil Nash
2016-06-10 19:37:27 +01:00
parent 3be950958c
commit 2a7d33a38c
5 changed files with 337 additions and 2 deletions

View File

@@ -16,6 +16,7 @@
#pragma clang diagnostic ignored "-Wweak-vtables"
#endif
#include "catch_stringref.hpp"
#include "../catch_session.hpp"
#include "catch_registry_hub.hpp"
#include "catch_notimplemented_exception.hpp"

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2016 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TWOBLUECUBES_CATCH_STRINGREF_H_INCLUDED
#define TWOBLUECUBES_CATCH_STRINGREF_H_INCLUDED
#include "internal/catch_suppress_warnings.h"
namespace Catch {
// A non-owning string class (similar to the forthcoming std::string_view)
// Note that, because a StringRef may be a substring of another string,
// it may not be null terminated. c_str() must return a null terminated
// string, however, and so the StringRef will internally take ownership
// (taking a copy), if necessary. This internal mutable is not externally
// visible - but does mean StringRefs should not be shared between
// threads.
class StringRef {
protected:
enum class Ownership {
FullStringRef,
SubStringRef,
FullStringOwned
};
using size_type = unsigned long;
char const* m_data;
size_type m_size;
Ownership m_ownership;
static StringRef s_emptyStringRef;
void takeOwnership();
void deleteIfOwned();
// Access for testing purposes only ////////////
friend auto rawCharData( StringRef const& stringRef ) -> char const*;
friend auto isOwned( StringRef const& stringRef ) -> bool;
friend auto isSubstring( StringRef const& stringRef ) -> bool;
////////////////////////////////////////////////
public: // construction/ assignment
StringRef();
StringRef( StringRef const& other );
StringRef( StringRef&& other );
StringRef( char const* rawChars );
StringRef( char const* rawChars, size_type size );
~StringRef();
auto operator = ( StringRef const& other ) -> StringRef&;
auto operator = ( StringRef&& other ) -> StringRef&;
public: // operators
auto operator == ( StringRef const& other ) const -> bool;
auto operator != ( StringRef const& other ) const -> bool;
auto operator[] ( size_type index ) const -> char {
return m_data[index];
}
public: // named queries
auto empty() const -> bool {
return m_size == 0;
}
auto size() const -> size_type {
return m_size;
}
auto c_str() const -> char const*;
public: // substrings and searches
auto substr( size_type start, size_type size ) const -> StringRef;
};
} // namespace Catch
#include "internal/catch_reenable_warnings.h"
#endif // TWOBLUECUBES_CATCH_STRINGREF_H_INCLUDED

View File

@@ -0,0 +1,112 @@
#include "catch_stringref.h"
#include <cstring>
namespace Catch {
StringRef StringRef::s_emptyStringRef = "";
StringRef::StringRef()
: StringRef( s_emptyStringRef )
{}
StringRef::StringRef( StringRef const& other )
: m_data( other.m_data ),
m_size( other.m_size ),
m_ownership( other.m_ownership )
{
if( m_ownership == Ownership::FullStringOwned )
m_ownership = Ownership::FullStringRef;
}
StringRef::StringRef( StringRef&& other )
: m_data( other.m_data ),
m_size( other.m_size ),
m_ownership( other.m_ownership )
{
if( m_ownership == Ownership::FullStringOwned )
other.m_ownership = Ownership::FullStringRef;
}
StringRef::StringRef( char const* rawChars )
: m_data( rawChars ),
m_size( std::strlen( rawChars ) ),
m_ownership( Ownership::FullStringRef )
{}
StringRef::StringRef( char const* rawChars, size_type size )
: m_data( rawChars ),
m_size( size ),
m_ownership( Ownership::SubStringRef )
{
size_type rawSize = std::strlen( rawChars );
if( rawSize < size )
size = rawSize;
if( rawSize == size )
m_ownership = Ownership::FullStringRef;
}
StringRef::~StringRef() {
deleteIfOwned();
}
void StringRef::deleteIfOwned() {
if( m_ownership == Ownership::FullStringOwned )
delete m_data;
}
auto StringRef::operator = ( StringRef const& other ) -> StringRef& {
if( &other == this )
return *this;
deleteIfOwned();
m_data = other.m_data;
m_size = other.m_size;
if( other.m_ownership == Ownership::FullStringOwned )
m_ownership = Ownership::FullStringRef;
else
m_ownership = other.m_ownership;
return *this;
}
auto StringRef::operator = ( StringRef&& other ) -> StringRef& {
if( &other == this )
return *this;
deleteIfOwned();
m_data = other.m_data;
m_size = other.m_size;
m_ownership = other.m_ownership;
if( other.m_ownership == Ownership::FullStringOwned )
other.m_ownership = Ownership::FullStringRef;
return *this;
}
auto StringRef::c_str() const -> char const* {
if( m_ownership == Ownership::SubStringRef )
const_cast<StringRef*>( this )->takeOwnership();
return m_data;
}
void StringRef::takeOwnership() {
if( m_ownership != Ownership::FullStringOwned ) {
char* data = new char[m_size+1];
std::memcpy( data, m_data, m_size );
data[m_size] = '\0';
m_data = data;
m_ownership = Ownership::FullStringOwned;
}
}
auto StringRef::substr( size_type start, size_type size ) const -> StringRef {
if( start < m_size )
return StringRef( m_data+start, size );
else
return StringRef();
}
auto StringRef::operator == ( StringRef const& other ) const -> bool {
return size() == other.size() &&
(std::strncmp( m_data, other.m_data, size() ) == 0);
}
auto StringRef::operator != ( StringRef const& other ) const -> bool {
return !operator==( other );
}
} // namespace Catch