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 );
/*= 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>

View file

@ -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( );