Strings - Library initalisation

The string library makes use of a Schwarz counter to ensure it is
correctly initialized.
This commit is contained in:
Emmanuel BENOîT 2020-09-27 13:49:00 +02:00
parent a22cca26e2
commit 9a3d4ad4a7
2 changed files with 77 additions and 43 deletions

View file

@ -459,6 +459,19 @@ M_LSHIFT_OP( T_StringBuilder , float );
M_LSHIFT_OP( T_StringBuilder , double ); 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 } // namespace
#endif // _H_EBCL_STRINGS #endif // _H_EBCL_STRINGS
#include <ebcl/inline/Strings.hh> #include <ebcl/inline/Strings.hh>

View file

@ -38,16 +38,14 @@ M_ABSTRACT_POINTERS( StringDataInternal );
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
// T_EmptyString - Fake storage for the empty string // T_EmptyString_ - Fake storage for the empty string
class T_EmptyString final : public A_StringDataInternal class T_EmptyString_ final : public A_StringDataInternal
{ {
public: 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 // T_StringPool_ - Pool of string storage classes
class T_StringPool final class T_StringPool_ final
{ {
private: private:
T_HashIndex index_; T_HashIndex index_;
T_Array< T_OwnPtr< T_StaticString > > strings_; T_Array< T_OwnPtr< T_StaticString > > strings_;
mutable T_ReadWriteMutex mutex_;
public: public:
static T_StringPool Pool; T_StringPool_( );
static T_ReadWriteMutex Mutex;
T_StringPool( );
RP_StringDataInternal add( char const* data , uint32_t size ); RP_StringDataInternal add( char const* data , uint32_t size );
RP_StringDataInternal get( char const* data , uint32_t size ) const; 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 ); } 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 ==================================================*/ /*= UTF-8 UTILITY FUNCTIONS ==================================================*/
bool ebcl::UTF8IsValid( char const* string ) 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 ) : A_StringDataInternal( false )
{ {
data_ = nullptr; data_ = nullptr;
@ -949,8 +977,6 @@ T_EmptyString::T_EmptyString( )
length_ = 0; length_ = 0;
} }
T_EmptyString T_EmptyString::EmptyString;
/*= T_StaticString ===========================================================*/ /*= T_StaticString ===========================================================*/
@ -1076,27 +1102,22 @@ T_Substring::~T_Substring( )
} }
/*= T_StringPool =============================================================*/ /*= T_StringPool_ ============================================================*/
T_StringPool T_StringPool::Pool; T_StringPool_::T_StringPool_( )
T_ReadWriteMutex T_StringPool::Mutex;
/*----------------------------------------------------------------------------*/
T_StringPool::T_StringPool( )
: index_( 16384 , 4096 , 4096 ) , strings_( 4096 ) : 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 ); T_ReadLock lock{ mutex_ };
const auto hash( HashData( (uint8_t const*) data , size ) ); const auto hash{ HashData( (uint8_t const*) data , size ) };
const auto idx( find( data , size , hash ) ); const auto idx{ find( data , size , hash ) };
if ( idx == T_HashIndex::INVALID_INDEX ) { if ( idx == T_HashIndex::INVALID_INDEX ) {
const T_WriteLock wLock( lock.upgrade( ) ); const T_WriteLock wLock{ lock.upgrade( ) };
index_.add( hash ); index_.add( hash );
const auto str( strings_.add( NewOwned< T_StaticString >( data , size ) ) ); const auto str( strings_.add( NewOwned< T_StaticString >( data , size ) ) );
return strings_[ str ].get( ); 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 T_ReadLock lock{ mutex_ };
const auto hash( HashData( reinterpret_cast< uint8_t const* >( data ) , size ) ); const auto hash{ HashData( reinterpret_cast< uint8_t const* >( data ) , size ) };
const auto idx( find( data , size , hash ) ); const auto idx{ find( data , size , hash ) };
if ( idx == T_HashIndex::INVALID_INDEX ) { if ( idx == T_HashIndex::INVALID_INDEX ) {
return nullptr; 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 ); uint32_t idx = index_.first( hash );
while ( idx != T_HashIndex::INVALID_INDEX ) { while ( idx != T_HashIndex::INVALID_INDEX ) {
@ -1220,16 +1241,16 @@ bool T_StringIterator::next( )
/*= T_String =================================================================*/ /*= T_String =================================================================*/
T_String::T_String( ) noexcept T_String::T_String( ) noexcept
: data_( &T_EmptyString::EmptyString ) : data_( &EmptyString_ )
{ } { }
T_String::T_String( char const* initial ) T_String::T_String( char const* initial )
{ {
if ( initial == nullptr || *initial == 0 ) { if ( initial == nullptr || *initial == 0 ) {
data_ = &T_EmptyString::EmptyString; data_ = &EmptyString_;
} else { } else {
const uint32_t len( strlen( initial ) ); const uint32_t len( strlen( initial ) );
data_ = T_StringPool::Pool.get( initial , len ); data_ = StringPool_.get( initial , len );
if ( data_ == nullptr ) { if ( data_ == nullptr ) {
data_ = new T_DynamicString( initial , len , false ); 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 ) T_String::T_String( char const* data , uint32_t size , bool nodup )
{ {
if ( data == nullptr || size == 0 ) { if ( data == nullptr || size == 0 ) {
data_ = &T_EmptyString::EmptyString; data_ = &EmptyString_;
} else { } else {
data_ = new T_DynamicString( data , size , nodup ); 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 T_String::T_String( T_String&& source ) noexcept
: data_( &T_EmptyString::EmptyString ) : data_( &EmptyString_ )
{ {
swap( *this , source ); swap( *this , source );
} }
@ -1285,7 +1306,7 @@ T_String& T_String::operator= ( T_String&& string ) noexcept
assert( data_ != nullptr ); assert( data_ != nullptr );
dynamic_cast< RP_StringDataInternal >( data_ )->removeUser( ); dynamic_cast< RP_StringDataInternal >( data_ )->removeUser( );
data_ = string.data_; data_ = string.data_;
string.data_ = &T_EmptyString::EmptyString; string.data_ = &EmptyString_;
return *this; return *this;
} }
@ -1334,7 +1355,7 @@ T_String T_String::Pooled( char const* data , uint32_t size )
assert( data != nullptr ); assert( data != nullptr );
T_String s; T_String s;
if ( size ) { if ( size ) {
s.data_ = T_StringPool::Pool.add( data , size ); s.data_ = StringPool_.add( data , size );
} }
return s; return s;
} }
@ -1345,7 +1366,7 @@ T_String& T_String::addToPool( )
{ {
const auto d( dynamic_cast< RP_StringDataInternal >( data_ ) ); const auto d( dynamic_cast< RP_StringDataInternal >( data_ ) );
if ( d->poolable ) { if ( d->poolable ) {
data_ = T_StringPool::Pool.add( d->data( ) , d->size( ) ); data_ = StringPool_.add( d->data( ) , d->size( ) );
d->removeUser( ); d->removeUser( );
} }
return *this; return *this;
@ -1356,7 +1377,7 @@ T_String& T_String::usePool( )
{ {
const auto d( dynamic_cast< RP_StringDataInternal >( data_ ) ); const auto d( dynamic_cast< RP_StringDataInternal >( data_ ) );
if ( d->poolable ) { 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 ) { if ( nd != nullptr ) {
data_ = nd; data_ = nd;
d->removeUser( ); d->removeUser( );