2024-04-10 20:29:18 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "UbaCompactTables.h"
# include "UbaBinaryReaderWriter.h"
namespace uba
{
2024-04-25 00:44:38 -04:00
CompactPathTable : : CompactPathTable ( u64 reserveSize , Version version , bool caseInsensitive , u64 reservePathCount , u64 reserveSegmentCount )
: m_reserveSize ( reserveSize )
, m_version ( version )
, m_caseInsensitive ( caseInsensitive )
2024-04-10 20:29:18 -04:00
{
2024-04-12 01:05:04 -04:00
if ( reservePathCount )
m_offsets . reserve ( reservePathCount ) ;
if ( reserveSegmentCount )
m_segmentOffsets . reserve ( reserveSegmentCount ) ;
2024-04-10 20:29:18 -04:00
}
2024-04-11 00:41:04 -04:00
u32 CompactPathTable : : Add ( const tchar * str , u64 strLen , u32 * outRequiredCasTableSize )
2024-04-10 20:29:18 -04:00
{
SCOPED_WRITE_LOCK ( m_lock , lock ) ;
2024-04-11 00:41:04 -04:00
u32 res = AddNoLock ( str , strLen ) ;
2024-04-10 20:29:18 -04:00
if ( outRequiredCasTableSize )
* outRequiredCasTableSize = u32 ( m_mem . writtenSize ) ;
return res ;
}
2024-04-11 00:41:04 -04:00
u32 CompactPathTable : : AddNoLock ( const tchar * str , u64 strLen )
2024-04-10 20:29:18 -04:00
{
2024-04-11 00:41:04 -04:00
if ( ! m_mem . memory )
m_mem . Init ( m_reserveSize ) ;
if ( ! m_mem . writtenSize )
m_mem . AllocateNoLock ( 1 , 1 , TC ( " " ) ) ;
2024-04-10 20:29:18 -04:00
2024-04-11 00:41:04 -04:00
const tchar * stringKeyString = str ;
2024-04-10 20:29:18 -04:00
StringBuffer < MaxPath > tempStringKeyStr ;
2024-04-25 00:44:38 -04:00
if ( m_caseInsensitive )
2024-04-10 20:29:18 -04:00
stringKeyString = tempStringKeyStr . Append ( str ) . MakeLower ( ) . data ;
2024-04-11 00:41:04 -04:00
return InternalAdd ( str , stringKeyString , strLen ) ;
}
u32 CompactPathTable : : InternalAdd ( const tchar * str , const tchar * stringKeyString , u64 strLen )
{
2024-04-25 00:44:38 -04:00
StringKey key = ToStringKeyNoCheck ( stringKeyString , strLen ) ;
2024-04-10 20:29:18 -04:00
auto insres = m_offsets . try_emplace ( key ) ;
if ( ! insres . second )
return insres . first - > second ;
const tchar * seg = str ;
u32 parentOffset = 0 ;
2024-04-11 00:41:04 -04:00
for ( const tchar * it = str + strLen - 1 ; it > str ; - - it )
2024-04-10 20:29:18 -04:00
{
2024-04-11 00:41:04 -04:00
if ( * it ! = PathSeparator )
continue ;
parentOffset = InternalAdd ( str , stringKeyString , it - str ) ;
seg = it + 1 ;
break ;
2024-04-10 20:29:18 -04:00
}
u64 segLen = strLen - ( seg - str ) ;
u8 bytesForParent = Get7BitEncodedCount ( parentOffset ) ;
2024-04-12 01:05:04 -04:00
if ( m_version = = V0 )
{
u64 bytesForString = GetStringWriteSize ( seg , segLen ) ;
u64 memSize = bytesForParent + bytesForString ;
u8 * mem = ( u8 * ) m_mem . AllocateNoLock ( memSize , 1 , TC ( " " ) ) ;
BinaryWriter writer ( mem , 0 , memSize ) ;
writer . Write7BitEncoded ( parentOffset ) ;
writer . WriteString ( seg , segLen ) ;
insres . first - > second = u32 ( mem - m_mem . memory ) ;
return insres . first - > second ;
}
else
{
StringKey segmentKey = ToStringKeyNoCheck ( seg , segLen ) ;
auto insres2 = m_segmentOffsets . try_emplace ( segmentKey ) ;
if ( insres2 . second )
{
// Put string directly after current element and set segment offset to 0
u64 bytesForString = GetStringWriteSize ( seg , segLen ) ;
u64 memSize = bytesForParent + 1 + bytesForString ;
u8 * mem = ( u8 * ) m_mem . AllocateNoLock ( memSize , 1 , TC ( " " ) ) ;
BinaryWriter writer ( mem , 0 , memSize ) ;
writer . Write7BitEncoded ( parentOffset ) ;
writer . Write7BitEncoded ( 0 ) ;
writer . WriteString ( seg , segLen ) ;
u32 offset = u32 ( mem - m_mem . memory ) ;
insres . first - > second = offset ;
insres2 . first - > second = offset + bytesForParent + 1 ;
return offset ;
}
#if 0
StringBuffer < > temp ;
BinaryReader reader ( m_mem . memory , insres2 . first - > second , 1000 ) ;
reader . ReadString ( temp ) ;
UBA_ASSERT ( temp . count = = segLen & & wcsncmp ( temp . data , seg , segLen ) = = 0 ) ;
# endif
u32 strOffset = insres2 . first - > second ;
u64 memSize = bytesForParent + Get7BitEncodedCount ( strOffset ) ;
u8 * mem = ( u8 * ) m_mem . AllocateNoLock ( memSize , 1 , TC ( " " ) ) ;
BinaryWriter writer ( mem , 0 , memSize ) ;
writer . Write7BitEncoded ( parentOffset ) ;
writer . Write7BitEncoded ( strOffset ) ;
insres . first - > second = u32 ( mem - m_mem . memory ) ;
return insres . first - > second ;
}
2024-04-10 20:29:18 -04:00
}
void CompactPathTable : : GetString ( StringBufferBase & out , u64 offset ) const
{
2024-04-24 15:26:58 -04:00
# if UBA_DEBUG
{
SCOPED_READ_LOCK ( const_cast < CompactPathTable * > ( this ) - > m_lock , lock )
UBA_ASSERTF ( offset < m_mem . writtenSize , TC ( " Reading path key from offset %llu which is out of bounds (Max %llu) " ) , offset , m_mem . writtenSize ) ;
}
# endif
2024-04-10 20:29:18 -04:00
u32 offsets [ 256 ] ;
offsets [ 0 ] = u32 ( offset ) ;
u32 offsetCount = 0 ;
2024-04-11 00:41:04 -04:00
BinaryReader reader ( m_mem . memory , offset , m_mem . writtenSize ) ;
2024-04-10 20:29:18 -04:00
while ( offset )
{
+ + offsetCount ;
UBA_ASSERT ( offsetCount < sizeof_array ( offsets ) ) ;
2024-04-11 00:41:04 -04:00
reader . SetPosition ( offset ) ;
2024-04-10 20:29:18 -04:00
offset = ( u32 ) reader . Read7BitEncoded ( ) ;
offsets [ offsetCount ] = u32 ( offset ) ;
}
2024-04-12 01:05:04 -04:00
if ( m_version = = V0 )
2024-04-10 20:29:18 -04:00
{
2024-04-12 01:05:04 -04:00
bool isFirst = true ;
for ( u32 i = offsetCount ; i ; - - i )
{
reader . SetPosition ( offsets [ i - 1 ] ) ;
reader . Read7BitEncoded ( ) ;
2024-04-10 20:29:18 -04:00
2024-04-12 01:05:04 -04:00
if ( ! isFirst )
out . Append ( PathSeparator ) ;
isFirst = false ;
reader . ReadString ( out ) ;
}
}
else
{
bool isFirst = true ;
for ( u32 i = offsetCount ; i ; - - i )
{
reader . SetPosition ( offsets [ i - 1 ] ) ;
reader . Read7BitEncoded ( ) ;
u32 strOffset = u32 ( reader . Read7BitEncoded ( ) ) ;
if ( strOffset ! = 0 )
reader . SetPosition ( strOffset ) ;
if ( ! isFirst )
out . Append ( PathSeparator ) ;
isFirst = false ;
reader . ReadString ( out ) ;
}
2024-04-10 20:29:18 -04:00
}
}
u8 * CompactPathTable : : GetMemory ( )
{
return m_mem . memory ;
}
u32 CompactPathTable : : GetSize ( )
{
SCOPED_READ_LOCK ( m_lock , lock2 )
return u32 ( m_mem . writtenSize ) ;
}
void CompactPathTable : : ReadMem ( BinaryReader & reader , bool populateLookup )
{
if ( ! m_mem . memory )
m_mem . Init ( m_reserveSize ) ;
u64 writtenSize = m_mem . writtenSize ;
u64 left = reader . GetLeft ( ) ;
2024-04-11 00:41:04 -04:00
void * mem = m_mem . AllocateNoLock ( left , 1 , TC ( " " ) ) ;
2024-04-10 20:29:18 -04:00
reader . ReadBytes ( mem , left ) ;
if ( ! populateLookup )
return ;
BinaryReader reader2 ( m_mem . memory , writtenSize , m_mem . writtenSize ) ;
if ( ! writtenSize )
reader2 . Skip ( 1 ) ;
2024-04-12 01:05:04 -04:00
if ( m_version = = V0 )
2024-04-10 20:29:18 -04:00
{
2024-04-12 01:05:04 -04:00
while ( reader2 . GetLeft ( ) )
{
u32 offset = u32 ( reader2 . GetPosition ( ) ) ;
reader2 . Read7BitEncoded ( ) ;
reader2 . SkipString ( ) ;
StringBuffer < > str ;
GetString ( str , offset ) ;
2024-04-25 00:44:38 -04:00
if ( m_caseInsensitive )
2024-04-12 01:05:04 -04:00
str . MakeLower ( ) ;
m_offsets . try_emplace ( ToStringKeyNoCheck ( str . data , str . count ) , offset ) ;
}
}
else
{
while ( reader2 . GetLeft ( ) )
{
u32 offset = u32 ( reader2 . GetPosition ( ) ) ;
reader2 . Read7BitEncoded ( ) ;
u64 stringOffset = reader2 . Read7BitEncoded ( ) ;
if ( ! stringOffset )
{
u32 strOffset = u32 ( reader2 . GetPosition ( ) ) ;
StringBuffer < > seg ;
reader2 . ReadString ( seg ) ;
m_segmentOffsets . try_emplace ( ToStringKeyNoCheck ( seg . data , seg . count ) , strOffset ) ;
}
StringBuffer < > str ;
GetString ( str , offset ) ;
2024-04-25 00:44:38 -04:00
if ( m_caseInsensitive )
2024-04-12 01:05:04 -04:00
str . MakeLower ( ) ;
m_offsets . try_emplace ( ToStringKeyNoCheck ( str . data , str . count ) , offset ) ;
}
2024-04-10 20:29:18 -04:00
}
}
void CompactPathTable : : Swap ( CompactPathTable & other )
{
m_offsets . swap ( other . m_offsets ) ;
2024-04-12 01:05:04 -04:00
m_segmentOffsets . swap ( other . m_segmentOffsets ) ;
2024-04-10 20:29:18 -04:00
m_mem . Swap ( other . m_mem ) ;
u64 rs = m_reserveSize ;
m_reserveSize = other . m_reserveSize ;
other . m_reserveSize = rs ;
2024-04-12 01:05:04 -04:00
Version v = m_version ;
m_version = other . m_version ;
other . m_version = v ;
2024-04-10 20:29:18 -04:00
}
CompactCasKeyTable : : CompactCasKeyTable ( u64 reserveSize , u64 reserveOffsetsCount )
{
m_reserveSize = reserveSize ;
if ( reserveOffsetsCount )
m_offsets . reserve ( reserveOffsetsCount ) ;
}
u32 CompactCasKeyTable : : Add ( const CasKey & casKey , u64 stringOffset , u32 * outRequiredCasTableSize )
{
SCOPED_WRITE_LOCK ( m_lock , lock2 )
if ( ! m_mem . memory )
m_mem . Init ( m_reserveSize ) ;
auto insres = m_offsets . try_emplace ( { casKey , u32 ( stringOffset ) } ) ;
if ( insres . second )
{
u8 bytesForStringOffset = Get7BitEncodedCount ( stringOffset ) ;
2024-04-11 00:41:04 -04:00
u8 * mem = ( u8 * ) m_mem . AllocateNoLock ( bytesForStringOffset + sizeof ( CasKey ) , 1 , TC ( " " ) ) ;
2024-04-10 20:29:18 -04:00
BinaryWriter writer ( mem , 0 , 1000 ) ;
writer . Write7BitEncoded ( stringOffset ) ;
writer . WriteCasKey ( casKey ) ;
insres . first - > second = u32 ( mem - m_mem . memory ) ;
if ( outRequiredCasTableSize )
* outRequiredCasTableSize = ( u32 ) m_mem . writtenSize ;
}
else if ( outRequiredCasTableSize )
{
2024-04-29 01:40:34 -04:00
BinaryReader reader ( m_mem . memory , insres . first - > second , ~ 0u ) ;
2024-04-10 20:29:18 -04:00
reader . Read7BitEncoded ( ) ;
* outRequiredCasTableSize = Max ( * outRequiredCasTableSize , u32 ( reader . GetPosition ( ) + sizeof ( CasKey ) ) ) ;
}
return insres . first - > second ;
}
void CompactCasKeyTable : : GetKey ( CasKey & outKey , u64 offset ) const
{
2024-04-29 01:40:34 -04:00
BinaryReader reader ( m_mem . memory , offset , ~ 0u ) ;
2024-04-10 20:29:18 -04:00
reader . Read7BitEncoded ( ) ;
outKey = reader . ReadCasKey ( ) ;
}
void CompactCasKeyTable : : GetPathAndKey ( StringBufferBase & outPath , CasKey & outKey , const CompactPathTable & pathTable , u64 offset ) const
{
2024-04-24 15:26:58 -04:00
# if UBA_DEBUG
{
SCOPED_READ_LOCK ( const_cast < CompactCasKeyTable * > ( this ) - > m_lock , lock )
UBA_ASSERTF ( offset + sizeof ( CasKey ) < m_mem . writtenSize , TC ( " Reading cas key from offset %llu which is out of bounds (Max %llu) " ) , offset + sizeof ( CasKey ) , m_mem . writtenSize ) ;
}
# endif
2024-04-29 01:40:34 -04:00
BinaryReader reader ( m_mem . memory , offset , ~ 0u ) ;
2024-04-10 20:29:18 -04:00
u32 stringOffset = ( u32 ) reader . Read7BitEncoded ( ) ;
outKey = reader . ReadCasKey ( ) ;
pathTable . GetString ( outPath , stringOffset ) ;
}
u8 * CompactCasKeyTable : : GetMemory ( )
{
return m_mem . memory ;
}
u32 CompactCasKeyTable : : GetSize ( )
{
SCOPED_READ_LOCK ( m_lock , lock2 )
return u32 ( m_mem . writtenSize ) ;
}
void CompactCasKeyTable : : ReadMem ( BinaryReader & reader , bool populateLookup )
{
if ( ! m_mem . memory )
m_mem . Init ( m_reserveSize ) ;
u64 writtenSize = m_mem . writtenSize ;
u64 left = reader . GetLeft ( ) ;
2024-04-11 00:41:04 -04:00
void * mem = m_mem . AllocateNoLock ( left , 1 , TC ( " " ) ) ;
2024-04-10 20:29:18 -04:00
reader . ReadBytes ( mem , left ) ;
if ( ! populateLookup )
return ;
BinaryReader reader2 ( m_mem . memory , writtenSize , m_mem . writtenSize ) ;
while ( reader2 . GetLeft ( ) )
{
u32 offset = u32 ( reader2 . GetPosition ( ) ) ;
u64 stringOffset = reader2 . Read7BitEncoded ( ) ;
CasKey casKey = reader2 . ReadCasKey ( ) ;
m_offsets . try_emplace ( { casKey , u32 ( stringOffset ) } , offset ) ;
}
}
void CompactCasKeyTable : : Swap ( CompactCasKeyTable & other )
{
m_offsets . swap ( other . m_offsets ) ;
m_mem . Swap ( other . m_mem ) ;
u64 rs = m_reserveSize ;
m_reserveSize = other . m_reserveSize ;
other . m_reserveSize = rs ;
}
}