Strings - Library initalisation
The string library makes use of a Schwarz counter to ensure it is correctly initialized.
This commit is contained in:
parent
a22cca26e2
commit
9a3d4ad4a7
2 changed files with 77 additions and 43 deletions
|
@ -459,6 +459,19 @@ M_LSHIFT_OP( T_StringBuilder , float );
|
|||
M_LSHIFT_OP( T_StringBuilder , double );
|
||||
|
||||
|
||||
/*= STRING LIBRARY INITIALIZER ===============================================*/
|
||||
/* A few things in the string library need to be initialised as soon as
|
||||
* anything that may use it is loaded. This includes the string pool and the
|
||||
* "empty string" constant.
|
||||
*/
|
||||
|
||||
static struct T_StringLibInitializer
|
||||
{
|
||||
T_StringLibInitializer( );
|
||||
~T_StringLibInitializer( );
|
||||
} StringLibInitializer;
|
||||
|
||||
|
||||
} // namespace
|
||||
#endif // _H_EBCL_STRINGS
|
||||
#include <ebcl/inline/Strings.hh>
|
||||
|
|
107
src/Strings.cc
107
src/Strings.cc
|
@ -38,16 +38,14 @@ M_ABSTRACT_POINTERS( StringDataInternal );
|
|||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_EmptyString - Fake storage for the empty string
|
||||
class T_EmptyString final : public A_StringDataInternal
|
||||
// T_EmptyString_ - Fake storage for the empty string
|
||||
class T_EmptyString_ final : public A_StringDataInternal
|
||||
{
|
||||
public:
|
||||
static T_EmptyString EmptyString;
|
||||
T_EmptyString_( );
|
||||
|
||||
T_EmptyString( );
|
||||
|
||||
T_EmptyString( T_EmptyString const& ) = delete;
|
||||
T_EmptyString( T_EmptyString&& other ) = delete;
|
||||
T_EmptyString_( T_EmptyString_ const& ) = delete;
|
||||
T_EmptyString_( T_EmptyString_&& other ) = delete;
|
||||
};
|
||||
|
||||
|
||||
|
@ -120,18 +118,16 @@ class T_Substring final : public A_RefCountedString
|
|||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
// T_StringPool - Pool of string storage classes
|
||||
class T_StringPool final
|
||||
// T_StringPool_ - Pool of string storage classes
|
||||
class T_StringPool_ final
|
||||
{
|
||||
private:
|
||||
T_HashIndex index_;
|
||||
T_Array< T_OwnPtr< T_StaticString > > strings_;
|
||||
mutable T_ReadWriteMutex mutex_;
|
||||
|
||||
public:
|
||||
static T_StringPool Pool;
|
||||
static T_ReadWriteMutex Mutex;
|
||||
|
||||
T_StringPool( );
|
||||
T_StringPool_( );
|
||||
|
||||
RP_StringDataInternal add( char const* data , uint32_t size );
|
||||
RP_StringDataInternal get( char const* data , uint32_t size ) const;
|
||||
|
@ -146,6 +142,38 @@ class T_StringPool final
|
|||
namespace ebcl { M_DECLARE_HASH( A_StringDataInternal ); }
|
||||
|
||||
|
||||
/*= LIBRARY STATE AND INITIALIZATION =========================================*/
|
||||
|
||||
namespace {
|
||||
|
||||
uint64_t StringLibCounter_;
|
||||
|
||||
T_VarStorage< T_StringPool_ > StringPoolBuffer_;
|
||||
T_VarStorage< T_EmptyString_ > EmptyStringBuffer_;
|
||||
|
||||
T_StringPool_& StringPool_ = reinterpret_cast< T_StringPool_& >( StringPoolBuffer_ );
|
||||
T_EmptyString_& EmptyString_ = reinterpret_cast< T_EmptyString_& >( EmptyStringBuffer_ );
|
||||
|
||||
}
|
||||
|
||||
T_StringLibInitializer::T_StringLibInitializer( )
|
||||
{
|
||||
if ( StringLibCounter_ ++ == 0 ) {
|
||||
new (&StringPool_) T_StringPool_( );
|
||||
new (&EmptyString_) T_EmptyString_( );
|
||||
}
|
||||
}
|
||||
|
||||
T_StringLibInitializer::~T_StringLibInitializer( )
|
||||
{
|
||||
if ( -- StringLibCounter_ == 0 ) {
|
||||
( &StringPool_ )->~T_StringPool_( );
|
||||
( &EmptyString_ )->~T_EmptyString_( );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*= UTF-8 UTILITY FUNCTIONS ==================================================*/
|
||||
|
||||
bool ebcl::UTF8IsValid( char const* string )
|
||||
|
@ -938,9 +966,9 @@ inline M_DEFINE_HASH( A_StringDataInternal )
|
|||
}
|
||||
|
||||
|
||||
/*= T_EmptyString ============================================================*/
|
||||
/*= T_EmptyString_ ============================================================*/
|
||||
|
||||
T_EmptyString::T_EmptyString( )
|
||||
T_EmptyString_::T_EmptyString_( )
|
||||
: A_StringDataInternal( false )
|
||||
{
|
||||
data_ = nullptr;
|
||||
|
@ -949,8 +977,6 @@ T_EmptyString::T_EmptyString( )
|
|||
length_ = 0;
|
||||
}
|
||||
|
||||
T_EmptyString T_EmptyString::EmptyString;
|
||||
|
||||
|
||||
/*= T_StaticString ===========================================================*/
|
||||
|
||||
|
@ -1076,27 +1102,22 @@ T_Substring::~T_Substring( )
|
|||
}
|
||||
|
||||
|
||||
/*= T_StringPool =============================================================*/
|
||||
/*= T_StringPool_ ============================================================*/
|
||||
|
||||
T_StringPool T_StringPool::Pool;
|
||||
T_ReadWriteMutex T_StringPool::Mutex;
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
T_StringPool::T_StringPool( )
|
||||
T_StringPool_::T_StringPool_( )
|
||||
: index_( 16384 , 4096 , 4096 ) , strings_( 4096 )
|
||||
{ }
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
RP_StringDataInternal T_StringPool::add( char const* data , uint32_t size )
|
||||
RP_StringDataInternal T_StringPool_::add( char const* data , uint32_t size )
|
||||
{
|
||||
T_ReadLock lock( T_StringPool::Mutex );
|
||||
const auto hash( HashData( (uint8_t const*) data , size ) );
|
||||
const auto idx( find( data , size , hash ) );
|
||||
T_ReadLock lock{ mutex_ };
|
||||
const auto hash{ HashData( (uint8_t const*) data , size ) };
|
||||
const auto idx{ find( data , size , hash ) };
|
||||
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
const T_WriteLock wLock( lock.upgrade( ) );
|
||||
const T_WriteLock wLock{ lock.upgrade( ) };
|
||||
index_.add( hash );
|
||||
const auto str( strings_.add( NewOwned< T_StaticString >( data , size ) ) );
|
||||
return strings_[ str ].get( );
|
||||
|
@ -1107,11 +1128,11 @@ RP_StringDataInternal T_StringPool::add( char const* data , uint32_t size )
|
|||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
RP_StringDataInternal T_StringPool::get( char const* data , uint32_t size ) const
|
||||
RP_StringDataInternal T_StringPool_::get( char const* data , uint32_t size ) const
|
||||
{
|
||||
const T_ReadLock lock( T_StringPool::Mutex );
|
||||
const auto hash( HashData( reinterpret_cast< uint8_t const* >( data ) , size ) );
|
||||
const auto idx( find( data , size , hash ) );
|
||||
const T_ReadLock lock{ mutex_ };
|
||||
const auto hash{ HashData( reinterpret_cast< uint8_t const* >( data ) , size ) };
|
||||
const auto idx{ find( data , size , hash ) };
|
||||
|
||||
if ( idx == T_HashIndex::INVALID_INDEX ) {
|
||||
return nullptr;
|
||||
|
@ -1122,7 +1143,7 @@ RP_StringDataInternal T_StringPool::get( char const* data , uint32_t size ) cons
|
|||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
uint32_t T_StringPool::find( char const* data , uint32_t sz , uint32_t hash ) const
|
||||
uint32_t T_StringPool_::find( char const* data , uint32_t sz , uint32_t hash ) const
|
||||
{
|
||||
uint32_t idx = index_.first( hash );
|
||||
while ( idx != T_HashIndex::INVALID_INDEX ) {
|
||||
|
@ -1220,16 +1241,16 @@ bool T_StringIterator::next( )
|
|||
/*= T_String =================================================================*/
|
||||
|
||||
T_String::T_String( ) noexcept
|
||||
: data_( &T_EmptyString::EmptyString )
|
||||
: data_( &EmptyString_ )
|
||||
{ }
|
||||
|
||||
T_String::T_String( char const* initial )
|
||||
{
|
||||
if ( initial == nullptr || *initial == 0 ) {
|
||||
data_ = &T_EmptyString::EmptyString;
|
||||
data_ = &EmptyString_;
|
||||
} else {
|
||||
const uint32_t len( strlen( initial ) );
|
||||
data_ = T_StringPool::Pool.get( initial , len );
|
||||
data_ = StringPool_.get( initial , len );
|
||||
if ( data_ == nullptr ) {
|
||||
data_ = new T_DynamicString( initial , len , false );
|
||||
}
|
||||
|
@ -1250,7 +1271,7 @@ T_String::T_String( T_StringBuilder const& sb )
|
|||
T_String::T_String( char const* data , uint32_t size , bool nodup )
|
||||
{
|
||||
if ( data == nullptr || size == 0 ) {
|
||||
data_ = &T_EmptyString::EmptyString;
|
||||
data_ = &EmptyString_;
|
||||
} else {
|
||||
data_ = new T_DynamicString( data , size , nodup );
|
||||
}
|
||||
|
@ -1265,7 +1286,7 @@ T_String::T_String( T_String const& source )
|
|||
}
|
||||
|
||||
T_String::T_String( T_String&& source ) noexcept
|
||||
: data_( &T_EmptyString::EmptyString )
|
||||
: data_( &EmptyString_ )
|
||||
{
|
||||
swap( *this , source );
|
||||
}
|
||||
|
@ -1285,7 +1306,7 @@ T_String& T_String::operator= ( T_String&& string ) noexcept
|
|||
assert( data_ != nullptr );
|
||||
dynamic_cast< RP_StringDataInternal >( data_ )->removeUser( );
|
||||
data_ = string.data_;
|
||||
string.data_ = &T_EmptyString::EmptyString;
|
||||
string.data_ = &EmptyString_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1334,7 +1355,7 @@ T_String T_String::Pooled( char const* data , uint32_t size )
|
|||
assert( data != nullptr );
|
||||
T_String s;
|
||||
if ( size ) {
|
||||
s.data_ = T_StringPool::Pool.add( data , size );
|
||||
s.data_ = StringPool_.add( data , size );
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
@ -1345,7 +1366,7 @@ T_String& T_String::addToPool( )
|
|||
{
|
||||
const auto d( dynamic_cast< RP_StringDataInternal >( data_ ) );
|
||||
if ( d->poolable ) {
|
||||
data_ = T_StringPool::Pool.add( d->data( ) , d->size( ) );
|
||||
data_ = StringPool_.add( d->data( ) , d->size( ) );
|
||||
d->removeUser( );
|
||||
}
|
||||
return *this;
|
||||
|
@ -1356,7 +1377,7 @@ T_String& T_String::usePool( )
|
|||
{
|
||||
const auto d( dynamic_cast< RP_StringDataInternal >( data_ ) );
|
||||
if ( d->poolable ) {
|
||||
const auto nd( T_StringPool::Pool.get( d->data( ) , d->size( ) ) );
|
||||
const auto nd( StringPool_.get( d->data( ) , d->size( ) ) );
|
||||
if ( nd != nullptr ) {
|
||||
data_ = nd;
|
||||
d->removeUser( );
|
||||
|
|
Loading…
Reference in a new issue