2016-03-01 15:47:10 +00:00
/*
* * dobjtype . cpp
* * Implements the type information class
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 1998 - 2010 Randy Heit
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
// HEADER FILES ------------------------------------------------------------
# include <float.h>
# include <limits>
# include "dobject.h"
# include "i_system.h"
2016-09-20 16:27:47 +00:00
# include "serializer.h"
2016-03-01 15:47:10 +00:00
# include "actor.h"
# include "templates.h"
# include "autosegs.h"
# include "v_text.h"
# include "a_pickups.h"
# include "d_player.h"
2016-09-20 16:27:47 +00:00
# include "doomerrors.h"
2016-03-01 15:47:10 +00:00
# include "fragglescript/t_fs.h"
2016-11-30 12:36:13 +00:00
# include "a_keys.h"
2016-03-01 15:47:10 +00:00
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
2016-06-08 08:56:11 +00:00
EXTERN_CVAR ( Bool , strictdecorate ) ;
2016-03-01 15:47:10 +00:00
// PUBLIC DATA DEFINITIONS -------------------------------------------------
2017-02-08 19:37:22 +00:00
FMemArena ClassDataAllocator ( 32768 ) ; // use this for all static class data that can be released in bulk when the type system is shut down.
2017-01-23 18:09:36 +00:00
2016-03-01 15:47:10 +00:00
FTypeTable TypeTable ;
TArray < PClass * > PClass : : AllClasses ;
2017-01-31 12:41:23 +00:00
TArray < VMFunction * * > PClass : : FunctionPtrList ;
2016-03-01 15:47:10 +00:00
bool PClass : : bShutdown ;
2017-01-13 12:51:47 +00:00
bool PClass : : bVMOperational ;
2016-03-01 15:47:10 +00:00
PErrorType * TypeError ;
2016-12-05 12:24:42 +00:00
PErrorType * TypeAuto ;
2016-03-01 15:47:10 +00:00
PVoidType * TypeVoid ;
PInt * TypeSInt8 , * TypeUInt8 ;
PInt * TypeSInt16 , * TypeUInt16 ;
PInt * TypeSInt32 , * TypeUInt32 ;
PBool * TypeBool ;
PFloat * TypeFloat32 , * TypeFloat64 ;
PString * TypeString ;
PName * TypeName ;
PSound * TypeSound ;
PColor * TypeColor ;
2016-11-21 12:45:33 +00:00
PTextureID * TypeTextureID ;
PSpriteID * TypeSpriteID ;
2016-03-01 15:47:10 +00:00
PStatePointer * TypeState ;
2017-02-05 12:14:22 +00:00
PPointer * TypeFont ;
2016-11-14 13:12:27 +00:00
PStateLabel * TypeStateLabel ;
2016-10-09 13:47:31 +00:00
PStruct * TypeVector2 ;
PStruct * TypeVector3 ;
2016-11-21 11:38:39 +00:00
PStruct * TypeColorStruct ;
2016-11-28 17:15:18 +00:00
PStruct * TypeStringStruct ;
2016-10-21 17:18:39 +00:00
PPointer * TypeNullPtr ;
2017-01-10 23:57:31 +00:00
PPointer * TypeVoidPtr ;
2016-03-01 15:47:10 +00:00
// PRIVATE DATA DEFINITIONS ------------------------------------------------
2017-02-07 13:48:27 +00:00
// A harmless non-nullptr FlatPointer for classes without pointers.
2016-03-01 15:47:10 +00:00
static const size_t TheEnd = ~ ( size_t ) 0 ;
// CODE --------------------------------------------------------------------
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PErrorType , false , false )
IMPLEMENT_CLASS ( PVoidType , false , false )
2016-03-01 15:47:10 +00:00
void DumpTypeTable ( )
{
int used = 0 ;
int min = INT_MAX ;
int max = 0 ;
int all = 0 ;
int lens [ 10 ] = { 0 } ;
for ( size_t i = 0 ; i < countof ( TypeTable . TypeHash ) ; + + i )
{
int len = 0 ;
Printf ( " %4zu: " , i ) ;
2017-02-07 13:48:27 +00:00
for ( PType * ty = TypeTable . TypeHash [ i ] ; ty ! = nullptr ; ty = ty - > HashNext )
2016-03-01 15:47:10 +00:00
{
2017-01-23 18:09:36 +00:00
Printf ( " -> %s " , ty - > DescriptiveName ( ) ) ;
2016-03-01 15:47:10 +00:00
len + + ;
all + + ;
}
if ( len ! = 0 )
{
used + + ;
if ( len < min )
min = len ;
if ( len > max )
max = len ;
}
if ( len < ( int ) countof ( lens ) )
{
lens [ len ] + + ;
}
Printf ( " \n " ) ;
}
Printf ( " Used buckets: %d/%lu (%.2f%%) for %d entries \n " , used , countof ( TypeTable . TypeHash ) , double ( used ) / countof ( TypeTable . TypeHash ) * 100 , all ) ;
Printf ( " Min bucket size: %d \n " , min ) ;
Printf ( " Max bucket size: %d \n " , max ) ;
Printf ( " Avg bucket size: %.2f \n " , double ( all ) / used ) ;
int j , k ;
for ( k = countof ( lens ) - 1 ; k > 0 ; - - k )
if ( lens [ k ] )
break ;
for ( j = 0 ; j < = k ; + + j )
Printf ( " Buckets of len %d: %d (%.2f%%) \n " , j , lens [ j ] , j ! = 0 ? double ( lens [ j ] ) / used * 100 : - 1.0 ) ;
}
/* PType ******************************************************************/
2017-02-08 21:43:20 +00:00
IMPLEMENT_CLASS ( PType , true , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PType Parameterized Constructor
//
//==========================================================================
PType : : PType ( unsigned int size , unsigned int align )
2017-02-07 13:48:27 +00:00
: Size ( size ) , Align ( align ) , HashNext ( nullptr )
2016-03-01 15:47:10 +00:00
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Type " ;
2016-10-28 08:44:01 +00:00
loadOp = OP_NOP ;
storeOp = OP_NOP ;
moveOp = OP_NOP ;
RegType = REGT_NIL ;
2016-10-28 12:43:29 +00:00
RegCount = 1 ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PType Destructor
//
//==========================================================================
PType : : ~ PType ( )
{
}
//==========================================================================
2016-04-03 04:10:43 +00:00
//
// PType :: WriteValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
void PType : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
2016-04-03 04:10:43 +00:00
{
assert ( 0 & & " Cannot write value for this type " ) ;
}
//==========================================================================
//
// PType :: ReadValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PType : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
2016-04-03 04:10:43 +00:00
{
assert ( 0 & & " Cannot read value for this type " ) ;
return false ;
}
2016-04-03 22:45:04 +00:00
//==========================================================================
//
// PType :: SetDefaultValue
//
//==========================================================================
void PType : : SetDefaultValue ( void * base , unsigned offset , TArray < FTypeAndOffset > * stroffs ) const
{
}
2016-11-17 21:21:08 +00:00
//==========================================================================
//
// PType :: SetDefaultValue
//
//==========================================================================
void PType : : SetPointer ( void * base , unsigned offset , TArray < size_t > * stroffs ) const
{
}
2017-02-07 13:48:27 +00:00
void PType : : SetPointerArray ( void * base , unsigned offset , TArray < size_t > * stroffs ) const
{
}
2016-04-03 22:45:04 +00:00
//==========================================================================
//
// PType :: InitializeValue
//
//==========================================================================
void PType : : InitializeValue ( void * addr , const void * def ) const
{
}
//==========================================================================
//
// PType :: DestroyValue
//
//==========================================================================
void PType : : DestroyValue ( void * addr ) const
{
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PType :: SetValue
//
//==========================================================================
void PType : : SetValue ( void * addr , int val )
{
2016-03-30 03:05:25 +00:00
assert ( 0 & & " Cannot set int value for this type " ) ;
}
void PType : : SetValue ( void * addr , double val )
{
assert ( 0 & & " Cannot set float value for this type " ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PType :: GetValue
//
//==========================================================================
int PType : : GetValueInt ( void * addr ) const
{
assert ( 0 & & " Cannot get value for this type " ) ;
return 0 ;
}
2016-03-30 03:24:59 +00:00
double PType : : GetValueFloat ( void * addr ) const
{
assert ( 0 & & " Cannot get value for this type " ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PType :: IsMatch
//
//==========================================================================
bool PType : : IsMatch ( intptr_t id1 , intptr_t id2 ) const
{
return false ;
}
//==========================================================================
//
// PType :: GetTypeIDs
//
//==========================================================================
void PType : : GetTypeIDs ( intptr_t & id1 , intptr_t & id2 ) const
{
id1 = 0 ;
id2 = 0 ;
}
2016-10-16 17:42:22 +00:00
//==========================================================================
//
// PType :: GetTypeIDs
//
//==========================================================================
const char * PType : : DescriptiveName ( ) const
{
return mDescriptiveName . GetChars ( ) ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PType :: StaticInit STATIC
//
//==========================================================================
void PType : : StaticInit ( )
{
// Create types and add them type the type table.
TypeTable . AddType ( TypeError = new PErrorType ) ;
2016-12-05 12:24:42 +00:00
TypeTable . AddType ( TypeAuto = new PErrorType ( 2 ) ) ;
2016-03-01 15:47:10 +00:00
TypeTable . AddType ( TypeVoid = new PVoidType ) ;
TypeTable . AddType ( TypeSInt8 = new PInt ( 1 , false ) ) ;
TypeTable . AddType ( TypeUInt8 = new PInt ( 1 , true ) ) ;
TypeTable . AddType ( TypeSInt16 = new PInt ( 2 , false ) ) ;
TypeTable . AddType ( TypeUInt16 = new PInt ( 2 , true ) ) ;
TypeTable . AddType ( TypeSInt32 = new PInt ( 4 , false ) ) ;
TypeTable . AddType ( TypeUInt32 = new PInt ( 4 , true ) ) ;
TypeTable . AddType ( TypeBool = new PBool ) ;
TypeTable . AddType ( TypeFloat32 = new PFloat ( 4 ) ) ;
TypeTable . AddType ( TypeFloat64 = new PFloat ( 8 ) ) ;
TypeTable . AddType ( TypeString = new PString ) ;
TypeTable . AddType ( TypeName = new PName ) ;
TypeTable . AddType ( TypeSound = new PSound ) ;
TypeTable . AddType ( TypeColor = new PColor ) ;
TypeTable . AddType ( TypeState = new PStatePointer ) ;
2016-11-14 13:12:27 +00:00
TypeTable . AddType ( TypeStateLabel = new PStateLabel ) ;
2016-10-21 17:18:39 +00:00
TypeTable . AddType ( TypeNullPtr = new PPointer ) ;
2016-11-21 12:45:33 +00:00
TypeTable . AddType ( TypeSpriteID = new PSpriteID ) ;
TypeTable . AddType ( TypeTextureID = new PTextureID ) ;
2016-03-01 15:47:10 +00:00
2017-01-10 23:57:31 +00:00
TypeVoidPtr = NewPointer ( TypeVoid , false ) ;
2016-11-28 17:15:18 +00:00
TypeColorStruct = NewStruct ( " @ColorStruct " , nullptr ) ; //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value.
2017-01-23 18:09:36 +00:00
TypeStringStruct = NewNativeStruct ( " Stringstruct " , nullptr ) ;
2017-02-05 12:14:22 +00:00
TypeFont = NewPointer ( NewNativeStruct ( " Font " , nullptr ) ) ;
2016-11-21 11:38:39 +00:00
# ifdef __BIG_ENDIAN__
TypeColorStruct - > AddField ( NAME_a , TypeUInt8 ) ;
TypeColorStruct - > AddField ( NAME_r , TypeUInt8 ) ;
TypeColorStruct - > AddField ( NAME_g , TypeUInt8 ) ;
TypeColorStruct - > AddField ( NAME_b , TypeUInt8 ) ;
# else
TypeColorStruct - > AddField ( NAME_b , TypeUInt8 ) ;
TypeColorStruct - > AddField ( NAME_g , TypeUInt8 ) ;
TypeColorStruct - > AddField ( NAME_r , TypeUInt8 ) ;
TypeColorStruct - > AddField ( NAME_a , TypeUInt8 ) ;
# endif
2016-10-09 13:47:31 +00:00
TypeVector2 = new PStruct ( NAME_Vector2 , nullptr ) ;
TypeVector2 - > AddField ( NAME_X , TypeFloat64 ) ;
TypeVector2 - > AddField ( NAME_Y , TypeFloat64 ) ;
TypeTable . AddType ( TypeVector2 ) ;
2016-10-28 11:30:19 +00:00
TypeVector2 - > loadOp = OP_LV2 ;
TypeVector2 - > storeOp = OP_SV2 ;
TypeVector2 - > moveOp = OP_MOVEV2 ;
2016-10-28 12:43:29 +00:00
TypeVector2 - > RegType = REGT_FLOAT ;
TypeVector2 - > RegCount = 2 ;
2016-10-09 13:47:31 +00:00
TypeVector3 = new PStruct ( NAME_Vector3 , nullptr ) ;
TypeVector3 - > AddField ( NAME_X , TypeFloat64 ) ;
TypeVector3 - > AddField ( NAME_Y , TypeFloat64 ) ;
TypeVector3 - > AddField ( NAME_Z , TypeFloat64 ) ;
2016-11-22 18:20:31 +00:00
// allow accessing xy as a vector2. This is not supposed to be serialized so it's marked transient
TypeVector3 - > Symbols . AddSymbol ( new PField ( NAME_XY , TypeVector2 , VARF_Transient , 0 ) ) ;
2016-10-09 13:47:31 +00:00
TypeTable . AddType ( TypeVector3 ) ;
2016-10-28 12:43:29 +00:00
TypeVector3 - > loadOp = OP_LV3 ;
TypeVector3 - > storeOp = OP_SV3 ;
TypeVector3 - > moveOp = OP_MOVEV3 ;
TypeVector3 - > RegType = REGT_FLOAT ;
TypeVector3 - > RegCount = 3 ;
2016-10-09 13:47:31 +00:00
2017-01-23 18:09:36 +00:00
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_sByte , TypeSInt8 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Byte , TypeUInt8 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Short , TypeSInt16 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_uShort , TypeUInt16 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Int , TypeSInt32 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_uInt , TypeUInt32 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Bool , TypeBool ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Float , TypeFloat64 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Double , TypeFloat64 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Float32 , TypeFloat32 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Float64 , TypeFloat64 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_String , TypeString ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Name , TypeName ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Sound , TypeSound ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Color , TypeColor ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_State , TypeState ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Vector2 , TypeVector2 ) ) ;
Namespaces . GlobalNamespace - > Symbols . AddSymbol ( new PSymbolType ( NAME_Vector3 , TypeVector3 ) ) ;
2016-03-01 15:47:10 +00:00
}
/* PBasicType *************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PBasicType , true , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PBasicType Default Constructor
//
//==========================================================================
PBasicType : : PBasicType ( )
{
}
//==========================================================================
//
// PBasicType Parameterized Constructor
//
//==========================================================================
PBasicType : : PBasicType ( unsigned int size , unsigned int align )
: PType ( size , align )
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " BasicType " ;
2016-03-01 15:47:10 +00:00
}
/* PCompoundType **********************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PCompoundType , true , false )
2016-03-01 15:47:10 +00:00
/* PNamedType *************************************************************/
2017-02-08 21:43:20 +00:00
IMPLEMENT_CLASS ( PNamedType , true , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PNamedType :: IsMatch
//
//==========================================================================
bool PNamedType : : IsMatch ( intptr_t id1 , intptr_t id2 ) const
{
const DObject * outer = ( const DObject * ) id1 ;
FName name = ( ENamedName ) ( intptr_t ) id2 ;
return Outer = = outer & & TypeName = = name ;
}
//==========================================================================
//
// PNamedType :: GetTypeIDs
//
//==========================================================================
void PNamedType : : GetTypeIDs ( intptr_t & id1 , intptr_t & id2 ) const
{
id1 = ( intptr_t ) Outer ;
id2 = TypeName ;
}
/* PInt *******************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PInt , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PInt Default Constructor
//
//==========================================================================
PInt : : PInt ( )
2016-11-14 13:12:27 +00:00
: PBasicType ( 4 , 4 ) , Unsigned ( false ) , IntCompatible ( true )
2016-03-01 15:47:10 +00:00
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " SInt32 " ;
2016-03-01 15:47:10 +00:00
Symbols . AddSymbol ( new PSymbolConstNumeric ( NAME_Min , this , - 0x7FFFFFFF - 1 ) ) ;
Symbols . AddSymbol ( new PSymbolConstNumeric ( NAME_Max , this , 0x7FFFFFFF ) ) ;
2016-10-28 11:30:19 +00:00
SetOps ( ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PInt Parameterized Constructor
//
//==========================================================================
2016-11-14 13:12:27 +00:00
PInt : : PInt ( unsigned int size , bool unsign , bool compatible )
: PBasicType ( size , size ) , Unsigned ( unsign ) , IntCompatible ( compatible )
2016-03-01 15:47:10 +00:00
{
2016-10-16 17:42:22 +00:00
mDescriptiveName . Format ( " %cInt%d " , unsign ? ' U ' : ' S ' , size ) ;
2016-10-16 10:47:26 +00:00
MemberOnly = ( size < 4 ) ;
2016-03-01 15:47:10 +00:00
if ( ! unsign )
{
int maxval = ( 1 < < ( ( 8 * size ) - 1 ) ) - 1 ;
int minval = - maxval - 1 ;
Symbols . AddSymbol ( new PSymbolConstNumeric ( NAME_Min , this , minval ) ) ;
Symbols . AddSymbol ( new PSymbolConstNumeric ( NAME_Max , this , maxval ) ) ;
}
else
{
Symbols . AddSymbol ( new PSymbolConstNumeric ( NAME_Min , this , 0u ) ) ;
Symbols . AddSymbol ( new PSymbolConstNumeric ( NAME_Max , this , ( 1u < < ( 8 * size ) ) - 1 ) ) ;
}
2016-10-28 08:44:01 +00:00
SetOps ( ) ;
}
void PInt : : SetOps ( )
{
moveOp = OP_MOVE ;
RegType = REGT_INT ;
if ( Size = = 4 )
{
storeOp = OP_SW ;
loadOp = OP_LW ;
}
else if ( Size = = 1 )
{
storeOp = OP_SB ;
loadOp = Unsigned ? OP_LBU : OP_LB ;
}
else if ( Size = = 2 )
{
storeOp = OP_SH ;
loadOp = Unsigned ? OP_LHU : OP_LH ;
}
else
{
assert ( 0 & & " Unhandled integer size " ) ;
storeOp = OP_NOP ;
}
2016-03-01 15:47:10 +00:00
}
2016-04-03 04:10:43 +00:00
//==========================================================================
//
// PInt :: WriteValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
void PInt : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
if ( Size = = 8 & & Unsigned )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
// this is a special case that cannot be represented by an int64_t.
uint64_t val = * ( uint64_t * ) addr ;
ar ( key , val ) ;
2016-04-03 04:10:43 +00:00
}
2016-09-20 16:27:47 +00:00
else
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
int64_t val ;
switch ( Size )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
case 1 :
val = Unsigned ? * ( uint8_t * ) addr : * ( int8_t * ) addr ;
break ;
case 2 :
val = Unsigned ? * ( uint16_t * ) addr : * ( int16_t * ) addr ;
break ;
case 4 :
val = Unsigned ? * ( uint32_t * ) addr : * ( int32_t * ) addr ;
break ;
case 8 :
val = * ( int64_t * ) addr ;
break ;
default :
return ; // something invalid
2016-04-03 04:10:43 +00:00
}
2016-09-20 16:27:47 +00:00
ar ( key , val ) ;
2016-04-03 04:10:43 +00:00
}
}
//==========================================================================
//
// PInt :: ReadValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PInt : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
NumericValue val ;
2016-04-03 04:10:43 +00:00
2016-09-20 16:27:47 +00:00
ar ( key , val ) ;
if ( val . type = = NumericValue : : NM_invalid ) return false ; // not found or usable
if ( val . type = = NumericValue : : NM_float ) val . signedval = ( int64_t ) val . floatval ;
// No need to check the unsigned state here. Downcasting to smaller types will yield the same result for both.
2016-04-03 04:10:43 +00:00
switch ( Size )
{
2016-09-20 16:27:47 +00:00
case 1 :
* ( uint8_t * ) addr = ( uint8_t ) val . signedval ;
break ;
case 2 :
* ( uint16_t * ) addr = ( uint16_t ) val . signedval ;
break ;
case 4 :
* ( uint32_t * ) addr = ( uint32_t ) val . signedval ;
break ;
case 8 :
* ( uint64_t * ) addr = ( uint64_t ) val . signedval ;
break ;
default :
return false ; // something invalid
2016-04-03 04:10:43 +00:00
}
2016-09-20 16:27:47 +00:00
2016-04-03 04:10:43 +00:00
return true ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PInt :: SetValue
//
//==========================================================================
void PInt : : SetValue ( void * addr , int val )
{
assert ( ( ( intptr_t ) addr & ( Align - 1 ) ) = = 0 & & " unaligned address " ) ;
if ( Size = = 4 )
{
* ( int * ) addr = val ;
}
else if ( Size = = 1 )
{
* ( BYTE * ) addr = val ;
}
else if ( Size = = 2 )
{
* ( WORD * ) addr = val ;
}
else if ( Size = = 8 )
{
* ( QWORD * ) addr = val ;
}
else
{
assert ( 0 & & " Unhandled integer size " ) ;
}
}
2016-03-30 03:05:25 +00:00
void PInt : : SetValue ( void * addr , double val )
{
SetValue ( addr , ( int ) val ) ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PInt :: GetValueInt
//
//==========================================================================
int PInt : : GetValueInt ( void * addr ) const
{
assert ( ( ( intptr_t ) addr & ( Align - 1 ) ) = = 0 & & " unaligned address " ) ;
if ( Size = = 4 )
{
return * ( int * ) addr ;
}
else if ( Size = = 1 )
{
return Unsigned ? * ( BYTE * ) addr : * ( SBYTE * ) addr ;
}
else if ( Size = = 2 )
{
return Unsigned ? * ( WORD * ) addr : * ( SWORD * ) addr ;
}
else if ( Size = = 8 )
{ // truncated output
return ( int ) * ( QWORD * ) addr ;
}
else
{
assert ( 0 & & " Unhandled integer size " ) ;
return 0 ;
}
}
2016-03-30 03:24:59 +00:00
//==========================================================================
//
// PInt :: GetValueFloat
//
//==========================================================================
double PInt : : GetValueFloat ( void * addr ) const
{
return GetValueInt ( addr ) ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PInt :: GetStoreOp
//
//==========================================================================
/* PBool ******************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PBool , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PBool Default Constructor
//
//==========================================================================
PBool : : PBool ( )
: PInt ( sizeof ( bool ) , true )
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Bool " ;
MemberOnly = false ;
2016-03-01 15:47:10 +00:00
// Override the default max set by PInt's constructor
PSymbolConstNumeric * maxsym = static_cast < PSymbolConstNumeric * > ( Symbols . FindSymbol ( NAME_Max , false ) ) ;
2017-02-07 13:48:27 +00:00
assert ( maxsym ! = nullptr & & maxsym - > IsKindOf ( RUNTIME_CLASS ( PSymbolConstNumeric ) ) ) ;
2016-03-01 15:47:10 +00:00
maxsym - > Value = 1 ;
}
/* PFloat *****************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PFloat , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PFloat Default Constructor
//
//==========================================================================
PFloat : : PFloat ( )
: PBasicType ( 8 , 8 )
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Float " ;
2016-03-01 15:47:10 +00:00
SetDoubleSymbols ( ) ;
2016-10-28 08:44:01 +00:00
SetOps ( ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PFloat Parameterized Constructor
//
//==========================================================================
PFloat : : PFloat ( unsigned int size )
: PBasicType ( size , size )
{
2016-10-16 17:42:22 +00:00
mDescriptiveName . Format ( " Float%d " , size ) ;
2016-03-01 15:47:10 +00:00
if ( size = = 8 )
{
SetDoubleSymbols ( ) ;
}
else
{
assert ( size = = 4 ) ;
2016-10-16 10:47:26 +00:00
MemberOnly = true ;
2016-03-01 15:47:10 +00:00
SetSingleSymbols ( ) ;
}
2016-10-28 08:44:01 +00:00
SetOps ( ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PFloat :: SetDoubleSymbols
//
// Setup constant values for 64-bit floats.
//
//==========================================================================
void PFloat : : SetDoubleSymbols ( )
{
static const SymbolInitF symf [ ] =
{
{ NAME_Min_Normal , DBL_MIN } ,
{ NAME_Max , DBL_MAX } ,
{ NAME_Epsilon , DBL_EPSILON } ,
{ NAME_NaN , std : : numeric_limits < double > : : quiet_NaN ( ) } ,
{ NAME_Infinity , std : : numeric_limits < double > : : infinity ( ) } ,
{ NAME_Min_Denormal , std : : numeric_limits < double > : : denorm_min ( ) }
} ;
static const SymbolInitI symi [ ] =
{
{ NAME_Dig , DBL_DIG } ,
{ NAME_Min_Exp , DBL_MIN_EXP } ,
{ NAME_Max_Exp , DBL_MAX_EXP } ,
{ NAME_Mant_Dig , DBL_MANT_DIG } ,
{ NAME_Min_10_Exp , DBL_MIN_10_EXP } ,
{ NAME_Max_10_Exp , DBL_MAX_10_EXP }
} ;
SetSymbols ( symf , countof ( symf ) ) ;
SetSymbols ( symi , countof ( symi ) ) ;
}
//==========================================================================
//
// PFloat :: SetSingleSymbols
//
// Setup constant values for 32-bit floats.
//
//==========================================================================
void PFloat : : SetSingleSymbols ( )
{
static const SymbolInitF symf [ ] =
{
{ NAME_Min_Normal , FLT_MIN } ,
{ NAME_Max , FLT_MAX } ,
{ NAME_Epsilon , FLT_EPSILON } ,
{ NAME_NaN , std : : numeric_limits < float > : : quiet_NaN ( ) } ,
{ NAME_Infinity , std : : numeric_limits < float > : : infinity ( ) } ,
{ NAME_Min_Denormal , std : : numeric_limits < float > : : denorm_min ( ) }
} ;
static const SymbolInitI symi [ ] =
{
{ NAME_Dig , FLT_DIG } ,
{ NAME_Min_Exp , FLT_MIN_EXP } ,
{ NAME_Max_Exp , FLT_MAX_EXP } ,
{ NAME_Mant_Dig , FLT_MANT_DIG } ,
{ NAME_Min_10_Exp , FLT_MIN_10_EXP } ,
{ NAME_Max_10_Exp , FLT_MAX_10_EXP }
} ;
SetSymbols ( symf , countof ( symf ) ) ;
SetSymbols ( symi , countof ( symi ) ) ;
}
//==========================================================================
//
// PFloat :: SetSymbols
//
//==========================================================================
void PFloat : : SetSymbols ( const PFloat : : SymbolInitF * sym , size_t count )
{
for ( size_t i = 0 ; i < count ; + + i )
{
Symbols . AddSymbol ( new PSymbolConstNumeric ( sym [ i ] . Name , this , sym [ i ] . Value ) ) ;
}
}
void PFloat : : SetSymbols ( const PFloat : : SymbolInitI * sym , size_t count )
{
for ( size_t i = 0 ; i < count ; + + i )
{
Symbols . AddSymbol ( new PSymbolConstNumeric ( sym [ i ] . Name , this , sym [ i ] . Value ) ) ;
}
}
2016-04-03 04:10:43 +00:00
//==========================================================================
//
// PFloat :: WriteValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
void PFloat : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
2016-04-03 04:10:43 +00:00
{
if ( Size = = 8 )
{
2016-09-20 16:27:47 +00:00
ar ( key , * ( double * ) addr ) ;
2016-04-03 04:10:43 +00:00
}
else
{
2016-09-20 16:27:47 +00:00
ar ( key , * ( float * ) addr ) ;
2016-04-03 04:10:43 +00:00
}
}
//==========================================================================
//
// PFloat :: ReadValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PFloat : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
NumericValue val ;
2016-04-03 04:10:43 +00:00
2016-09-20 16:27:47 +00:00
ar ( key , val ) ;
if ( val . type = = NumericValue : : NM_invalid ) return false ; // not found or usable
else if ( val . type = = NumericValue : : NM_signed ) val . floatval = ( double ) val . signedval ;
else if ( val . type = = NumericValue : : NM_unsigned ) val . floatval = ( double ) val . unsignedval ;
2016-04-03 04:10:43 +00:00
2016-09-20 16:27:47 +00:00
if ( Size = = 8 )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
* ( double * ) addr = val . floatval ;
2016-04-03 04:10:43 +00:00
}
2016-09-20 16:27:47 +00:00
else
{
* ( float * ) addr = ( float ) val . floatval ;
}
return true ;
2016-04-03 04:10:43 +00:00
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PFloat :: SetValue
//
//==========================================================================
void PFloat : : SetValue ( void * addr , int val )
2016-03-30 03:05:25 +00:00
{
return SetValue ( addr , ( double ) val ) ;
}
void PFloat : : SetValue ( void * addr , double val )
2016-03-01 15:47:10 +00:00
{
assert ( ( ( intptr_t ) addr & ( Align - 1 ) ) = = 0 & & " unaligned address " ) ;
if ( Size = = 4 )
{
* ( float * ) addr = ( float ) val ;
}
else
{
assert ( Size = = 8 ) ;
* ( double * ) addr = val ;
}
}
//==========================================================================
//
// PFloat :: GetValueInt
//
//==========================================================================
int PFloat : : GetValueInt ( void * addr ) const
2016-03-30 03:24:59 +00:00
{
return xs_ToInt ( GetValueFloat ( addr ) ) ;
}
//==========================================================================
//
// PFloat :: GetValueFloat
//
//==========================================================================
double PFloat : : GetValueFloat ( void * addr ) const
2016-03-01 15:47:10 +00:00
{
assert ( ( ( intptr_t ) addr & ( Align - 1 ) ) = = 0 & & " unaligned address " ) ;
if ( Size = = 4 )
{
2016-03-30 03:24:59 +00:00
return * ( float * ) addr ;
2016-03-01 15:47:10 +00:00
}
else
{
assert ( Size = = 8 ) ;
2016-03-30 03:24:59 +00:00
return * ( double * ) addr ;
2016-03-01 15:47:10 +00:00
}
}
//==========================================================================
//
// PFloat :: GetStoreOp
//
//==========================================================================
2016-10-28 08:44:01 +00:00
void PFloat : : SetOps ( )
2016-03-01 15:47:10 +00:00
{
if ( Size = = 4 )
{
2016-10-28 08:44:01 +00:00
storeOp = OP_SSP ;
loadOp = OP_LSP ;
2016-03-01 15:47:10 +00:00
}
else
{
assert ( Size = = 8 ) ;
2016-10-28 08:44:01 +00:00
storeOp = OP_SDP ;
loadOp = OP_LDP ;
2016-03-01 15:47:10 +00:00
}
2016-10-28 08:44:01 +00:00
moveOp = OP_MOVEF ;
RegType = REGT_FLOAT ;
2016-03-01 15:47:10 +00:00
}
/* PString ****************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PString , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PString Default Constructor
//
//==========================================================================
PString : : PString ( )
2016-11-17 23:42:04 +00:00
: PBasicType ( sizeof ( FString ) , alignof ( FString ) )
2016-03-01 15:47:10 +00:00
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " String " ;
2016-10-28 12:43:29 +00:00
storeOp = OP_SS ;
loadOp = OP_LS ;
moveOp = OP_MOVES ;
RegType = REGT_STRING ;
2016-03-01 15:47:10 +00:00
}
2016-04-03 04:10:43 +00:00
//==========================================================================
//
// PString :: WriteValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
void PString : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
ar ( key , * ( FString * ) addr ) ;
2016-04-03 04:10:43 +00:00
}
//==========================================================================
//
// PString :: ReadValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PString : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
const char * cptr ;
ar . StringPtr ( key , cptr ) ;
if ( cptr = = nullptr )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
return false ;
2016-04-03 04:10:43 +00:00
}
else
{
2016-09-20 16:27:47 +00:00
* ( FString * ) addr = cptr ;
return true ;
2016-04-03 04:10:43 +00:00
}
}
2016-04-03 22:45:04 +00:00
//==========================================================================
//
// PString :: SetDefaultValue
//
//==========================================================================
void PString : : SetDefaultValue ( void * base , unsigned offset , TArray < FTypeAndOffset > * special ) const
{
2016-10-09 23:18:47 +00:00
if ( base ! = nullptr ) new ( ( BYTE * ) base + offset ) FString ;
2017-02-07 13:48:27 +00:00
if ( special ! = nullptr )
2016-04-03 22:45:04 +00:00
{
special - > Push ( std : : make_pair ( this , offset ) ) ;
}
}
//==========================================================================
//
// PString :: InitializeValue
//
//==========================================================================
void PString : : InitializeValue ( void * addr , const void * def ) const
{
2016-10-09 23:18:47 +00:00
if ( def ! = nullptr )
{
new ( addr ) FString ( * ( FString * ) def ) ;
}
else
{
new ( addr ) FString ;
}
2016-04-03 22:45:04 +00:00
}
//==========================================================================
//
// PString :: DestroyValue
//
//==========================================================================
void PString : : DestroyValue ( void * addr ) const
{
( ( FString * ) addr ) - > ~ FString ( ) ;
}
2016-03-01 15:47:10 +00:00
/* PName ******************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PName , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PName Default Constructor
//
//==========================================================================
PName : : PName ( )
2016-11-14 13:12:27 +00:00
: PInt ( sizeof ( FName ) , true , false )
2016-03-01 15:47:10 +00:00
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Name " ;
2016-11-17 23:42:04 +00:00
assert ( sizeof ( FName ) = = alignof ( FName ) ) ;
2016-03-01 15:47:10 +00:00
}
2016-04-03 04:10:43 +00:00
//==========================================================================
//
// PName :: WriteValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
void PName : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
const char * cptr = ( ( const FName * ) addr ) - > GetChars ( ) ;
ar . StringPtr ( key , cptr ) ;
2016-04-03 04:10:43 +00:00
}
//==========================================================================
//
// PName :: ReadValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PName : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
const char * cptr ;
ar . StringPtr ( key , cptr ) ;
if ( cptr = = nullptr )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
return false ;
2016-04-03 04:10:43 +00:00
}
else
{
2016-09-20 16:27:47 +00:00
* ( FName * ) addr = FName ( cptr ) ;
return true ;
2016-04-03 04:10:43 +00:00
}
}
2016-11-21 12:45:33 +00:00
/* PSpriteID ******************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PSpriteID , false , false )
2016-11-21 12:45:33 +00:00
//==========================================================================
//
// PName Default Constructor
//
//==========================================================================
PSpriteID : : PSpriteID ( )
: PInt ( sizeof ( int ) , true , true )
{
mDescriptiveName = " SpriteID " ;
}
//==========================================================================
//
// PName :: WriteValue
//
//==========================================================================
void PSpriteID : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
{
int32_t val = * ( int * ) addr ;
ar . Sprite ( key , val , nullptr ) ;
}
//==========================================================================
//
// PName :: ReadValue
//
//==========================================================================
bool PSpriteID : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
{
int32_t val ;
ar . Sprite ( key , val , nullptr ) ;
* ( int * ) addr = val ;
return true ;
}
/* PTextureID ******************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PTextureID , false , false )
2016-11-21 12:45:33 +00:00
//==========================================================================
//
// PTextureID Default Constructor
//
//==========================================================================
PTextureID : : PTextureID ( )
: PInt ( sizeof ( FTextureID ) , true , false )
{
mDescriptiveName = " TextureID " ;
assert ( sizeof ( FTextureID ) = = alignof ( FTextureID ) ) ;
}
//==========================================================================
//
// PTextureID :: WriteValue
//
//==========================================================================
void PTextureID : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
{
FTextureID val = * ( FTextureID * ) addr ;
ar ( key , val ) ;
}
//==========================================================================
//
// PTextureID :: ReadValue
//
//==========================================================================
bool PTextureID : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
{
FTextureID val ;
ar ( key , val ) ;
* ( FTextureID * ) addr = val ;
return true ;
}
2016-03-01 15:47:10 +00:00
/* PSound *****************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PSound , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PSound Default Constructor
//
//==========================================================================
PSound : : PSound ( )
: PInt ( sizeof ( FSoundID ) , true )
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Sound " ;
2016-11-17 23:42:04 +00:00
assert ( sizeof ( FSoundID ) = = alignof ( FSoundID ) ) ;
2016-03-01 15:47:10 +00:00
}
2016-04-03 04:10:43 +00:00
//==========================================================================
//
// PSound :: WriteValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
void PSound : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
const char * cptr = * ( const FSoundID * ) addr ;
ar . StringPtr ( key , cptr ) ;
2016-04-03 04:10:43 +00:00
}
//==========================================================================
//
// PSound :: ReadValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PSound : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
const char * cptr ;
ar . StringPtr ( key , cptr ) ;
if ( cptr = = nullptr )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
return false ;
2016-04-03 04:10:43 +00:00
}
else
{
2016-09-20 16:27:47 +00:00
* ( FSoundID * ) addr = FSoundID ( cptr ) ;
return true ;
2016-04-03 04:10:43 +00:00
}
}
2016-03-01 15:47:10 +00:00
/* PColor *****************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PColor , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PColor Default Constructor
//
//==========================================================================
PColor : : PColor ( )
: PInt ( sizeof ( PalEntry ) , true )
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Color " ;
2016-11-17 23:42:04 +00:00
assert ( sizeof ( PalEntry ) = = alignof ( PalEntry ) ) ;
2016-03-01 15:47:10 +00:00
}
2016-11-14 13:12:27 +00:00
/* PStateLabel *****************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PStateLabel , false , false )
2016-11-14 13:12:27 +00:00
//==========================================================================
//
// PStateLabel Default Constructor
//
//==========================================================================
PStateLabel : : PStateLabel ( )
: PInt ( sizeof ( int ) , false , false )
{
mDescriptiveName = " StateLabel " ;
}
2016-03-01 15:47:10 +00:00
/* PPointer ***************************************************************/
2017-02-08 21:43:20 +00:00
IMPLEMENT_CLASS ( PPointer , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PPointer - Default Constructor
//
//==========================================================================
PPointer : : PPointer ( )
2017-02-07 13:48:27 +00:00
: PBasicType ( sizeof ( void * ) , alignof ( void * ) ) , PointedType ( nullptr ) , IsConst ( false )
2016-03-01 15:47:10 +00:00
{
2016-10-21 17:18:39 +00:00
mDescriptiveName = " NullPointer " ;
2016-10-28 08:44:01 +00:00
SetOps ( ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PPointer - Parameterized Constructor
//
//==========================================================================
2016-11-05 12:51:46 +00:00
PPointer : : PPointer ( PType * pointsat , bool isconst )
2016-11-17 23:42:04 +00:00
: PBasicType ( sizeof ( void * ) , alignof ( void * ) ) , PointedType ( pointsat ) , IsConst ( isconst )
2016-03-01 15:47:10 +00:00
{
2016-11-05 12:51:46 +00:00
mDescriptiveName . Format ( " Pointer<%s%s> " , pointsat - > DescriptiveName ( ) , isconst ? " readonly " : " " ) ;
2016-10-28 08:44:01 +00:00
SetOps ( ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PPointer :: GetStoreOp
//
//==========================================================================
2016-10-28 08:44:01 +00:00
void PPointer : : SetOps ( )
2016-03-01 15:47:10 +00:00
{
2016-10-28 08:44:01 +00:00
loadOp = ( PointedType & & PointedType - > IsKindOf ( RUNTIME_CLASS ( PClass ) ) ) ? OP_LO : OP_LP ;
2017-02-07 13:48:27 +00:00
// Non-destroyed thinkers are always guaranteed to be linked into the thinker chain so we don't need the write barrier for them.
storeOp = ( loadOp = = OP_LO & & ! static_cast < PClass * > ( PointedType ) - > IsDescendantOf ( RUNTIME_CLASS ( DThinker ) ) ) ? OP_SO : OP_SP ;
2016-10-28 08:44:01 +00:00
moveOp = OP_MOVEA ;
RegType = REGT_POINTER ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PPointer :: IsMatch
//
//==========================================================================
bool PPointer : : IsMatch ( intptr_t id1 , intptr_t id2 ) const
{
2016-11-05 16:14:16 +00:00
assert ( id2 = = 0 | | id2 = = 1 ) ;
2016-03-01 15:47:10 +00:00
PType * pointat = ( PType * ) id1 ;
2016-11-05 16:14:16 +00:00
return pointat = = PointedType & & ( ! ! id2 ) = = IsConst ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PPointer :: GetTypeIDs
//
//==========================================================================
void PPointer : : GetTypeIDs ( intptr_t & id1 , intptr_t & id2 ) const
{
id1 = ( intptr_t ) PointedType ;
id2 = 0 ;
}
2016-11-17 21:21:08 +00:00
//==========================================================================
//
2017-02-07 13:48:27 +00:00
// PPointer :: SetPointer
2016-11-17 21:21:08 +00:00
//
//==========================================================================
void PPointer : : SetPointer ( void * base , unsigned offset , TArray < size_t > * special ) const
{
if ( PointedType ! = nullptr & & PointedType - > IsKindOf ( RUNTIME_CLASS ( PClass ) ) )
{
// Add to the list of pointers for this class.
special - > Push ( offset ) ;
}
}
2016-04-03 04:10:43 +00:00
//==========================================================================
//
// PPointer :: WriteValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
void PPointer : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
2016-04-03 04:10:43 +00:00
{
2017-02-07 19:25:52 +00:00
if ( PointedType - > IsKindOf ( RUNTIME_CLASS ( PClass ) ) )
2017-01-02 12:37:09 +00:00
{
2017-02-07 19:25:52 +00:00
auto pt = static_cast < PClass * > ( PointedType ) ;
if ( pt - > IsDescendantOf ( RUNTIME_CLASS ( PClass ) ) )
{
ar ( key , * ( PClass * * ) addr ) ;
}
else
{
ar ( key , * ( DObject * * ) addr ) ;
}
2016-04-03 04:10:43 +00:00
}
else
{
assert ( 0 & & " Pointer points to a type we don't handle " ) ;
I_Error ( " Attempt to save pointer to unhandled type " ) ;
}
}
//==========================================================================
//
// PPointer :: ReadValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PPointer : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
2016-04-03 04:10:43 +00:00
{
2017-02-07 19:25:52 +00:00
if ( PointedType - > IsKindOf ( RUNTIME_CLASS ( PClass ) ) )
2016-04-03 04:10:43 +00:00
{
2017-02-07 19:25:52 +00:00
auto pt = static_cast < PClass * > ( PointedType ) ;
bool res = true ;
if ( pt - > IsDescendantOf ( RUNTIME_CLASS ( PClass ) ) )
{
: : Serialize ( ar , key , * ( PClass * * ) addr , ( PClass * * ) nullptr ) ;
}
else
{
: : Serialize ( ar , key , * ( DObject * * ) addr , nullptr , & res ) ;
}
2016-09-20 16:27:47 +00:00
return res ;
2016-04-03 04:10:43 +00:00
}
return false ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// NewPointer
//
// Returns a PPointer to an object of the specified type
//
//==========================================================================
2016-11-05 12:51:46 +00:00
PPointer * NewPointer ( PType * type , bool isconst )
2016-03-01 15:47:10 +00:00
{
size_t bucket ;
2016-11-05 12:51:46 +00:00
PType * ptype = TypeTable . FindType ( RUNTIME_CLASS ( PPointer ) , ( intptr_t ) type , isconst ? 1 : 0 , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( ptype = = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-11-27 14:50:58 +00:00
ptype = new PPointer ( type , isconst ) ;
2016-11-05 12:51:46 +00:00
TypeTable . AddType ( ptype , RUNTIME_CLASS ( PPointer ) , ( intptr_t ) type , isconst ? 1 : 0 , bucket ) ;
2016-03-01 15:47:10 +00:00
}
return static_cast < PPointer * > ( ptype ) ;
}
2016-11-21 18:36:14 +00:00
/* PStatePointer **********************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PStatePointer , false , false )
2016-11-21 18:36:14 +00:00
//==========================================================================
//
// PStatePointer Default Constructor
//
//==========================================================================
PStatePointer : : PStatePointer ( )
{
mDescriptiveName = " Pointer<State> " ;
PointedType = NewNativeStruct ( NAME_State , nullptr ) ;
IsConst = true ;
}
//==========================================================================
//
// PStatePointer :: WriteValue
//
//==========================================================================
void PStatePointer : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
{
ar ( key , * ( FState * * ) addr ) ;
}
//==========================================================================
//
// PStatePointer :: ReadValue
//
//==========================================================================
bool PStatePointer : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
{
bool res = false ;
: : Serialize ( ar , key , * ( FState * * ) addr , nullptr , & res ) ;
return res ;
}
2016-03-01 15:47:10 +00:00
/* PClassPointer **********************************************************/
2017-02-08 21:43:20 +00:00
IMPLEMENT_CLASS ( PClassPointer , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PClassPointer - Parameterized Constructor
//
//==========================================================================
PClassPointer : : PClassPointer ( PClass * restrict )
: PPointer ( RUNTIME_CLASS ( PClass ) ) , ClassRestriction ( restrict )
{
2016-10-16 20:32:52 +00:00
if ( restrict ) mDescriptiveName . Format ( " ClassPointer<%s> " , restrict - > TypeName . GetChars ( ) ) ;
else mDescriptiveName = " ClassPointer " ;
2017-02-07 13:48:27 +00:00
// class pointers do not need write barriers because all classes are stored in the global type table and won't get collected.
// This means we can use the cheapoer non-barriered opcodes here.
loadOp = OP_LOS ;
storeOp = OP_SP ;
2016-03-01 15:47:10 +00:00
}
2017-01-17 23:11:04 +00:00
//==========================================================================
//
// PClassPointer - isCompatible
//
//==========================================================================
bool PClassPointer : : isCompatible ( PType * type )
{
auto other = dyn_cast < PClassPointer > ( type ) ;
return ( other ! = nullptr & & other - > ClassRestriction - > IsDescendantOf ( ClassRestriction ) ) ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PClassPointer :: IsMatch
//
//==========================================================================
bool PClassPointer : : IsMatch ( intptr_t id1 , intptr_t id2 ) const
{
const PType * pointat = ( const PType * ) id1 ;
const PClass * classat = ( const PClass * ) id2 ;
assert ( pointat - > IsKindOf ( RUNTIME_CLASS ( PClass ) ) ) ;
return classat = = ClassRestriction ;
}
//==========================================================================
//
// PClassPointer :: GetTypeIDs
//
//==========================================================================
void PClassPointer : : GetTypeIDs ( intptr_t & id1 , intptr_t & id2 ) const
{
assert ( PointedType = = RUNTIME_CLASS ( PClass ) ) ;
id1 = ( intptr_t ) PointedType ;
id2 = ( intptr_t ) ClassRestriction ;
}
//==========================================================================
//
// NewClassPointer
//
// Returns a PClassPointer for the restricted type.
//
//==========================================================================
PClassPointer * NewClassPointer ( PClass * restrict )
{
size_t bucket ;
2016-03-03 21:09:19 +00:00
PType * ptype = TypeTable . FindType ( RUNTIME_CLASS ( PClassPointer ) , ( intptr_t ) RUNTIME_CLASS ( PClass ) , ( intptr_t ) restrict , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( ptype = = nullptr )
2016-03-01 15:47:10 +00:00
{
ptype = new PClassPointer ( restrict ) ;
2016-03-03 21:09:19 +00:00
TypeTable . AddType ( ptype , RUNTIME_CLASS ( PClassPointer ) , ( intptr_t ) RUNTIME_CLASS ( PClass ) , ( intptr_t ) restrict , bucket ) ;
2016-03-01 15:47:10 +00:00
}
return static_cast < PClassPointer * > ( ptype ) ;
}
/* PEnum ******************************************************************/
2017-02-08 21:43:20 +00:00
IMPLEMENT_CLASS ( PEnum , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PEnum - Default Constructor
//
//==========================================================================
PEnum : : PEnum ( )
2017-01-23 18:09:36 +00:00
: PInt ( 4 , false )
2016-03-01 15:47:10 +00:00
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Enum " ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PEnum - Parameterized Constructor
//
//==========================================================================
2016-10-07 11:59:29 +00:00
PEnum : : PEnum ( FName name , PTypeBase * outer )
2017-01-23 18:09:36 +00:00
: PInt ( 4 , false )
2016-03-01 15:47:10 +00:00
{
2017-01-23 18:09:36 +00:00
EnumName = name ;
Outer = outer ;
2016-10-16 17:42:22 +00:00
mDescriptiveName . Format ( " Enum<%s> " , name . GetChars ( ) ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// NewEnum
//
// Returns a PEnum for the given name and container, making sure not to
// create duplicates.
//
//==========================================================================
2016-10-07 11:59:29 +00:00
PEnum * NewEnum ( FName name , PTypeBase * outer )
2016-03-01 15:47:10 +00:00
{
size_t bucket ;
2017-01-23 18:09:36 +00:00
if ( outer = = nullptr ) outer = Namespaces . GlobalNamespace ;
2016-03-01 15:47:10 +00:00
PType * etype = TypeTable . FindType ( RUNTIME_CLASS ( PEnum ) , ( intptr_t ) outer , ( intptr_t ) name , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( etype = = nullptr )
2016-03-01 15:47:10 +00:00
{
etype = new PEnum ( name , outer ) ;
TypeTable . AddType ( etype , RUNTIME_CLASS ( PEnum ) , ( intptr_t ) outer , ( intptr_t ) name , bucket ) ;
}
return static_cast < PEnum * > ( etype ) ;
}
/* PArray *****************************************************************/
2017-02-08 21:43:20 +00:00
IMPLEMENT_CLASS ( PArray , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PArray - Default Constructor
//
//==========================================================================
PArray : : PArray ( )
2017-02-07 13:48:27 +00:00
: ElementType ( nullptr ) , ElementCount ( 0 )
2016-03-01 15:47:10 +00:00
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Array " ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PArray - Parameterized Constructor
//
//==========================================================================
PArray : : PArray ( PType * etype , unsigned int ecount )
: ElementType ( etype ) , ElementCount ( ecount )
{
2016-10-16 17:42:22 +00:00
mDescriptiveName . Format ( " Array<%s>[%d] " , etype - > DescriptiveName ( ) , ecount ) ;
2016-03-01 15:47:10 +00:00
Align = etype - > Align ;
// Since we are concatenating elements together, the element size should
// also be padded to the nearest alignment.
ElementSize = ( etype - > Size + ( etype - > Align - 1 ) ) & ~ ( etype - > Align - 1 ) ;
Size = ElementSize * ecount ;
}
//==========================================================================
//
// PArray :: IsMatch
//
//==========================================================================
bool PArray : : IsMatch ( intptr_t id1 , intptr_t id2 ) const
{
const PType * elemtype = ( const PType * ) id1 ;
unsigned int count = ( unsigned int ) ( intptr_t ) id2 ;
return elemtype = = ElementType & & count = = ElementCount ;
}
//==========================================================================
//
// PArray :: GetTypeIDs
//
//==========================================================================
void PArray : : GetTypeIDs ( intptr_t & id1 , intptr_t & id2 ) const
{
id1 = ( intptr_t ) ElementType ;
id2 = ElementCount ;
}
2016-04-03 04:10:43 +00:00
//==========================================================================
//
// PArray :: WriteValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
void PArray : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
if ( ar . BeginArray ( key ) )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
const BYTE * addrb = ( const BYTE * ) addr ;
for ( unsigned i = 0 ; i < ElementCount ; + + i )
{
ElementType - > WriteValue ( ar , nullptr , addrb ) ;
addrb + = ElementSize ;
}
ar . EndArray ( ) ;
2016-04-03 04:10:43 +00:00
}
}
//==========================================================================
//
// PArray :: ReadValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PArray : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
if ( ar . BeginArray ( key ) )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
bool readsomething = false ;
unsigned count = ar . ArraySize ( ) ;
unsigned loop = MIN ( count , ElementCount ) ;
2016-04-03 04:10:43 +00:00
BYTE * addrb = ( BYTE * ) addr ;
2016-09-20 16:27:47 +00:00
for ( unsigned i = 0 ; i < loop ; i + + )
2016-04-03 04:10:43 +00:00
{
2016-09-20 17:45:32 +00:00
readsomething | = ElementType - > ReadValue ( ar , nullptr , addrb ) ;
2016-04-03 04:10:43 +00:00
addrb + = ElementSize ;
}
2016-09-20 17:45:32 +00:00
if ( loop < count )
2016-04-03 04:10:43 +00:00
{
2016-08-28 07:55:04 +00:00
DPrintf ( DMSG_WARNING , " Array on disk (%u) is bigger than in memory (%u) \n " ,
2016-04-03 04:10:43 +00:00
count , ElementCount ) ;
}
2016-09-20 16:27:47 +00:00
ar . EndArray ( ) ;
2016-04-03 04:10:43 +00:00
return readsomething ;
}
return false ;
}
2016-04-03 22:45:04 +00:00
//==========================================================================
//
// PArray :: SetDefaultValue
//
//==========================================================================
void PArray : : SetDefaultValue ( void * base , unsigned offset , TArray < FTypeAndOffset > * special ) const
{
for ( unsigned i = 0 ; i < ElementCount ; + + i )
{
ElementType - > SetDefaultValue ( base , offset + i * ElementSize , special ) ;
}
}
2016-11-17 21:21:08 +00:00
//==========================================================================
//
// PArray :: SetDefaultValue
//
//==========================================================================
void PArray : : SetPointer ( void * base , unsigned offset , TArray < size_t > * special ) const
{
for ( unsigned i = 0 ; i < ElementCount ; + + i )
{
ElementType - > SetPointer ( base , offset + i * ElementSize , special ) ;
}
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
2016-11-17 10:16:00 +00:00
// NewArray
2016-03-01 15:47:10 +00:00
//
2016-11-17 10:16:00 +00:00
// Returns a PArray for the given type and size, making sure not to create
2016-03-01 15:47:10 +00:00
// duplicates.
//
//==========================================================================
2016-11-17 10:16:00 +00:00
PArray * NewArray ( PType * type , unsigned int count )
2016-03-01 15:47:10 +00:00
{
size_t bucket ;
2016-11-17 10:16:00 +00:00
PType * atype = TypeTable . FindType ( RUNTIME_CLASS ( PArray ) , ( intptr_t ) type , count , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( atype = = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-11-17 10:16:00 +00:00
atype = new PArray ( type , count ) ;
TypeTable . AddType ( atype , RUNTIME_CLASS ( PArray ) , ( intptr_t ) type , count , bucket ) ;
2016-03-01 15:47:10 +00:00
}
2016-11-17 10:16:00 +00:00
return ( PArray * ) atype ;
2016-03-01 15:47:10 +00:00
}
2017-01-02 20:40:52 +00:00
/* PArray *****************************************************************/
IMPLEMENT_CLASS ( PResizableArray , false , false )
//==========================================================================
//
// PArray - Default Constructor
//
//==========================================================================
PResizableArray : : PResizableArray ( )
{
mDescriptiveName = " ResizableArray " ;
}
//==========================================================================
//
// PArray - Parameterized Constructor
//
//==========================================================================
PResizableArray : : PResizableArray ( PType * etype )
: PArray ( etype , 0 )
{
mDescriptiveName . Format ( " ResizableArray<%s> " , etype - > DescriptiveName ( ) ) ;
}
//==========================================================================
//
// PArray :: IsMatch
//
//==========================================================================
bool PResizableArray : : IsMatch ( intptr_t id1 , intptr_t id2 ) const
{
const PType * elemtype = ( const PType * ) id1 ;
unsigned int count = ( unsigned int ) ( intptr_t ) id2 ;
return elemtype = = ElementType & & count = = 0 ;
}
//==========================================================================
//
// PArray :: GetTypeIDs
//
//==========================================================================
void PResizableArray : : GetTypeIDs ( intptr_t & id1 , intptr_t & id2 ) const
{
id1 = ( intptr_t ) ElementType ;
id2 = 0 ;
}
//==========================================================================
//
// NewResizableArray
//
// Returns a PArray for the given type and size, making sure not to create
// duplicates.
//
//==========================================================================
PResizableArray * NewResizableArray ( PType * type )
{
size_t bucket ;
PType * atype = TypeTable . FindType ( RUNTIME_CLASS ( PResizableArray ) , ( intptr_t ) type , 0 , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( atype = = nullptr )
2017-01-02 20:40:52 +00:00
{
atype = new PResizableArray ( type ) ;
TypeTable . AddType ( atype , RUNTIME_CLASS ( PResizableArray ) , ( intptr_t ) type , 0 , bucket ) ;
}
return ( PResizableArray * ) atype ;
}
2016-03-01 15:47:10 +00:00
/* PDynArray **************************************************************/
2017-02-08 21:43:20 +00:00
IMPLEMENT_CLASS ( PDynArray , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PDynArray - Default Constructor
//
//==========================================================================
PDynArray : : PDynArray ( )
2017-02-07 13:48:27 +00:00
: ElementType ( nullptr )
2016-03-01 15:47:10 +00:00
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " DynArray " ;
2016-03-01 15:47:10 +00:00
Size = sizeof ( FArray ) ;
2016-11-17 23:42:04 +00:00
Align = alignof ( FArray ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PDynArray - Parameterized Constructor
//
//==========================================================================
2017-02-06 20:39:21 +00:00
PDynArray : : PDynArray ( PType * etype , PStruct * backing )
: ElementType ( etype ) , BackingType ( backing )
2016-03-01 15:47:10 +00:00
{
2016-10-16 17:42:22 +00:00
mDescriptiveName . Format ( " DynArray<%s> " , etype - > DescriptiveName ( ) ) ;
2016-03-01 15:47:10 +00:00
Size = sizeof ( FArray ) ;
2016-11-17 23:42:04 +00:00
Align = alignof ( FArray ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PDynArray :: IsMatch
//
//==========================================================================
bool PDynArray : : IsMatch ( intptr_t id1 , intptr_t id2 ) const
{
assert ( id2 = = 0 ) ;
const PType * elemtype = ( const PType * ) id1 ;
return elemtype = = ElementType ;
}
//==========================================================================
//
// PDynArray :: GetTypeIDs
//
//==========================================================================
void PDynArray : : GetTypeIDs ( intptr_t & id1 , intptr_t & id2 ) const
{
id1 = ( intptr_t ) ElementType ;
id2 = 0 ;
}
2017-02-07 13:48:27 +00:00
//==========================================================================
//
// PDynArray :: InitializeValue
//
//==========================================================================
void PDynArray : : InitializeValue ( void * addr , const void * deff ) const
{
const FArray * def = ( const FArray * ) deff ;
FArray * aray = ( FArray * ) addr ;
if ( def = = nullptr | | def - > Count = = 0 )
{
// Empty arrays do not need construction.
* aray = { nullptr , 0 , 0 } ;
}
else if ( ElementType - > GetRegType ( ) ! = REGT_STRING )
{
// These are just integral values which can be done without any constructor hackery.
size_t blocksize = ElementType - > Size * def - > Count ;
aray - > Array = M_Malloc ( blocksize ) ;
memcpy ( aray - > Array , def - > Array , blocksize ) ;
aray - > Most = aray - > Count = def - > Count ;
}
else
{
// non-empty string arrays require explicit construction.
new ( addr ) TArray < FString > ( * ( TArray < FString > * ) def ) ;
}
}
//==========================================================================
//
// PDynArray :: DestroyValue
//
//==========================================================================
void PDynArray : : DestroyValue ( void * addr ) const
{
FArray * aray = ( FArray * ) addr ;
if ( aray - > Array ! = nullptr )
{
if ( ElementType - > GetRegType ( ) ! = REGT_STRING )
{
M_Free ( aray - > Array ) ;
}
else
{
// Damn those cursed strings again. :(
( ( TArray < FString > * ) addr ) - > ~ TArray < FString > ( ) ;
}
}
aray - > Count = aray - > Most = 0 ;
aray - > Array = nullptr ;
}
//==========================================================================
//
// PDynArray :: SetDefaultValue
//
//==========================================================================
void PDynArray : : SetDefaultValue ( void * base , unsigned offset , TArray < FTypeAndOffset > * special ) const
{
memset ( ( char * ) base + offset , 0 , sizeof ( FArray ) ) ; // same as constructing an empty array.
if ( special ! = nullptr )
{
special - > Push ( std : : make_pair ( this , offset ) ) ;
}
}
//==========================================================================
//
// PDynArray :: SetPointer
//
//==========================================================================
void PDynArray : : SetPointerArray ( void * base , unsigned offset , TArray < size_t > * special ) const
{
2017-02-08 18:52:33 +00:00
if ( ElementType - > IsKindOf ( RUNTIME_CLASS ( PPointer ) ) & & ! ElementType - > IsKindOf ( RUNTIME_CLASS ( PClassPointer ) ) & & static_cast < PPointer * > ( ElementType ) - > PointedType - > IsKindOf ( RUNTIME_CLASS ( PClass ) ) )
2017-02-07 13:48:27 +00:00
{
// Add to the list of pointer arrays for this class.
special - > Push ( offset ) ;
}
}
//==========================================================================
//
// PDynArray :: WriteValue
//
//==========================================================================
void PDynArray : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
{
FArray * aray = ( FArray * ) addr ;
if ( aray - > Count > 0 )
{
if ( ar . BeginArray ( key ) )
{
const BYTE * addrb = ( const BYTE * ) aray - > Array ;
for ( unsigned i = 0 ; i < aray - > Count ; + + i )
{
ElementType - > WriteValue ( ar , nullptr , addrb ) ;
addrb + = ElementType - > Size ;
}
ar . EndArray ( ) ;
}
}
}
//==========================================================================
//
// PDynArray :: ReadValue
//
//==========================================================================
bool PDynArray : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
{
FArray * aray = ( FArray * ) addr ;
DestroyValue ( addr ) ; // note that even after calling this we still got a validly constructed empty array.
if ( ar . BeginArray ( key ) )
{
bool readsomething = false ;
unsigned count = ar . ArraySize ( ) ;
size_t blocksize = ElementType - > Size * count ;
aray - > Array = M_Malloc ( blocksize ) ;
memset ( aray - > Array , 0 , blocksize ) ;
aray - > Most = aray - > Count = count ;
BYTE * addrb = ( BYTE * ) aray - > Array ;
for ( unsigned i = 0 ; i < count ; i + + )
{
// Strings must be constructed first.
if ( ElementType - > GetRegType ( ) = = REGT_STRING ) new ( addrb ) FString ;
readsomething | = ElementType - > ReadValue ( ar , nullptr , addrb ) ;
addrb + = ElementType - > Size ;
}
ar . EndArray ( ) ;
return readsomething ;
}
return false ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// NewDynArray
//
// Creates a new DynArray of the given type, making sure not to create a
// duplicate.
//
//==========================================================================
PDynArray * NewDynArray ( PType * type )
{
size_t bucket ;
PType * atype = TypeTable . FindType ( RUNTIME_CLASS ( PDynArray ) , ( intptr_t ) type , 0 , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( atype = = nullptr )
2016-03-01 15:47:10 +00:00
{
2017-02-06 20:39:21 +00:00
FString backingname ;
switch ( type - > GetRegType ( ) )
{
case REGT_INT :
backingname . Format ( " DynArray_I%d " , type - > Size * 8 ) ;
break ;
case REGT_FLOAT :
backingname . Format ( " DynArray_F%d " , type - > Size * 8 ) ;
break ;
case REGT_STRING :
backingname = " DynArray_String " ;
break ;
case REGT_POINTER :
backingname = " DynArray_Ptr " ;
break ;
default :
I_Error ( " Unsupported dynamic array requested " ) ;
break ;
}
auto backing = NewNativeStruct ( backingname , nullptr ) ;
atype = new PDynArray ( type , backing ) ;
2016-03-01 15:47:10 +00:00
TypeTable . AddType ( atype , RUNTIME_CLASS ( PDynArray ) , ( intptr_t ) type , 0 , bucket ) ;
}
return ( PDynArray * ) atype ;
}
/* PMap *******************************************************************/
2017-02-08 21:43:20 +00:00
IMPLEMENT_CLASS ( PMap , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PMap - Default Constructor
//
//==========================================================================
PMap : : PMap ( )
2017-02-07 13:48:27 +00:00
: KeyType ( nullptr ) , ValueType ( nullptr )
2016-03-01 15:47:10 +00:00
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Map " ;
2016-03-01 15:47:10 +00:00
Size = sizeof ( FMap ) ;
2016-11-17 23:42:04 +00:00
Align = alignof ( FMap ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PMap - Parameterized Constructor
//
//==========================================================================
PMap : : PMap ( PType * keytype , PType * valtype )
: KeyType ( keytype ) , ValueType ( valtype )
{
2016-10-16 17:42:22 +00:00
mDescriptiveName . Format ( " Map<%s, %s> " , keytype - > DescriptiveName ( ) , valtype - > DescriptiveName ( ) ) ;
2016-03-01 15:47:10 +00:00
Size = sizeof ( FMap ) ;
2016-11-17 23:42:04 +00:00
Align = alignof ( FMap ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PMap :: IsMatch
//
//==========================================================================
bool PMap : : IsMatch ( intptr_t id1 , intptr_t id2 ) const
{
const PType * keyty = ( const PType * ) id1 ;
const PType * valty = ( const PType * ) id2 ;
return keyty = = KeyType & & valty = = ValueType ;
}
//==========================================================================
//
// PMap :: GetTypeIDs
//
//==========================================================================
void PMap : : GetTypeIDs ( intptr_t & id1 , intptr_t & id2 ) const
{
id1 = ( intptr_t ) KeyType ;
id2 = ( intptr_t ) ValueType ;
}
//==========================================================================
//
// NewMap
//
// Returns a PMap for the given key and value types, ensuring not to create
// duplicates.
//
//==========================================================================
PMap * NewMap ( PType * keytype , PType * valuetype )
{
size_t bucket ;
PType * maptype = TypeTable . FindType ( RUNTIME_CLASS ( PMap ) , ( intptr_t ) keytype , ( intptr_t ) valuetype , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( maptype = = nullptr )
2016-03-01 15:47:10 +00:00
{
maptype = new PMap ( keytype , valuetype ) ;
TypeTable . AddType ( maptype , RUNTIME_CLASS ( PMap ) , ( intptr_t ) keytype , ( intptr_t ) valuetype , bucket ) ;
}
return ( PMap * ) maptype ;
}
/* PStruct ****************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PStruct , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PStruct - Default Constructor
//
//==========================================================================
PStruct : : PStruct ( )
{
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Struct " ;
2016-10-28 12:43:29 +00:00
Size = 0 ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PStruct - Parameterized Constructor
//
//==========================================================================
2016-10-07 11:59:29 +00:00
PStruct : : PStruct ( FName name , PTypeBase * outer )
2016-03-01 15:47:10 +00:00
: PNamedType ( name , outer )
{
2016-10-16 17:42:22 +00:00
mDescriptiveName . Format ( " Struct<%s> " , name . GetChars ( ) ) ;
2016-10-28 12:43:29 +00:00
Size = 0 ;
2016-11-03 12:38:40 +00:00
HasNativeFields = false ;
2016-03-01 15:47:10 +00:00
}
2016-04-03 22:45:04 +00:00
//==========================================================================
//
// PStruct :: SetDefaultValue
//
//==========================================================================
void PStruct : : SetDefaultValue ( void * base , unsigned offset , TArray < FTypeAndOffset > * special ) const
{
for ( const PField * field : Fields )
{
2016-11-22 18:20:31 +00:00
if ( ! ( field - > Flags & VARF_Transient ) )
2016-04-03 22:45:04 +00:00
{
2016-11-03 12:38:40 +00:00
field - > Type - > SetDefaultValue ( base , unsigned ( offset + field - > Offset ) , special ) ;
2016-04-03 22:45:04 +00:00
}
}
}
2016-11-17 21:21:08 +00:00
//==========================================================================
//
// PStruct :: SetPointer
//
//==========================================================================
void PStruct : : SetPointer ( void * base , unsigned offset , TArray < size_t > * special ) const
{
for ( const PField * field : Fields )
{
2016-11-22 18:20:31 +00:00
if ( ! ( field - > Flags & VARF_Transient ) )
2016-11-17 21:21:08 +00:00
{
field - > Type - > SetPointer ( base , unsigned ( offset + field - > Offset ) , special ) ;
}
}
}
2016-04-03 04:10:43 +00:00
//==========================================================================
//
// PStruct :: WriteValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
void PStruct : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
if ( ar . BeginObject ( key ) )
{
WriteFields ( ar , addr , Fields ) ;
ar . EndObject ( ) ;
}
2016-04-03 04:10:43 +00:00
}
//==========================================================================
//
// PStruct :: ReadValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PStruct : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
if ( ar . BeginObject ( key ) )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
bool ret = ReadFields ( ar , addr ) ;
ar . EndObject ( ) ;
return ret ;
2016-04-03 04:10:43 +00:00
}
2016-09-20 16:27:47 +00:00
return false ;
2016-04-03 04:10:43 +00:00
}
//==========================================================================
//
// PStruct :: WriteFields STATIC
//
//==========================================================================
2016-09-20 16:27:47 +00:00
void PStruct : : WriteFields ( FSerializer & ar , const void * addr , const TArray < PField * > & fields )
2016-04-03 04:10:43 +00:00
{
for ( unsigned i = 0 ; i < fields . Size ( ) ; + + i )
{
const PField * field = fields [ i ] ;
2016-11-22 18:20:31 +00:00
// Skip fields without or with native serialization
if ( ! ( field - > Flags & VARF_Transient ) )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
field - > Type - > WriteValue ( ar , field - > SymbolName . GetChars ( ) , ( const BYTE * ) addr + field - > Offset ) ;
2016-04-03 04:10:43 +00:00
}
}
}
//==========================================================================
//
// PStruct :: ReadFields
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PStruct : : ReadFields ( FSerializer & ar , void * addr ) const
2016-04-03 04:10:43 +00:00
{
bool readsomething = false ;
2016-09-20 16:27:47 +00:00
bool foundsomething = false ;
const char * label ;
while ( ( label = ar . GetKey ( ) ) )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
foundsomething = true ;
2016-04-03 04:10:43 +00:00
const PSymbol * sym = Symbols . FindSymbol ( FName ( label , true ) , true ) ;
2017-02-07 13:48:27 +00:00
if ( sym = = nullptr )
2016-04-03 04:10:43 +00:00
{
2016-08-28 07:55:04 +00:00
DPrintf ( DMSG_ERROR , " Cannot find field %s in %s \n " ,
2016-04-03 04:10:43 +00:00
label , TypeName . GetChars ( ) ) ;
}
else if ( ! sym - > IsKindOf ( RUNTIME_CLASS ( PField ) ) )
{
2016-08-28 07:55:04 +00:00
DPrintf ( DMSG_ERROR , " Symbol %s in %s is not a field \n " ,
2016-04-03 04:10:43 +00:00
label , TypeName . GetChars ( ) ) ;
}
else
{
- removed the sequential processing of JSON objects because the benefit is too small.
After testing with a savegame on ZDCMP2 which is probably the largest map in existence, timing both methods resulted in a speed difference of less than 40 ms (70 vs 110 ms for reading all sectory, linedefs, sidedefs and objects).
This compares to an overall restoration time, including reloading the level, precaching all textures and setting everything up, of approx. 1.2 s, meaning an increase of 3% of the entire reloading time.
That's simply not worth all the negative side effects that may happen with a method that highly depends on proper code construction.
On the other hand, using random access means that a savegame version change is only needed now when the semantics of a field change, but not if some get added or deleted.
- do not I_Error out in the serializer unless caused by a programming error.
It is better to let the serializer finish, collect all the errors and I_Error out when the game is known to be in a stable enough state to allow unwinding.
2016-09-23 12:04:05 +00:00
readsomething | = static_cast < const PField * > ( sym ) - > Type - > ReadValue ( ar , nullptr ,
2016-04-03 04:10:43 +00:00
( BYTE * ) addr + static_cast < const PField * > ( sym ) - > Offset ) ;
}
}
2016-09-20 16:27:47 +00:00
return readsomething | | ! foundsomething ;
2016-04-03 04:10:43 +00:00
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PStruct :: AddField
//
// Appends a new field to the end of a struct. Returns either the new field
2017-02-07 13:48:27 +00:00
// or nullptr if a symbol by that name already exists.
2016-03-01 15:47:10 +00:00
//
//==========================================================================
PField * PStruct : : AddField ( FName name , PType * type , DWORD flags )
{
2016-11-03 12:38:40 +00:00
PField * field = new PField ( name , type , flags ) ;
2016-03-01 15:47:10 +00:00
// The new field is added to the end of this struct, alignment permitting.
field - > Offset = ( Size + ( type - > Align - 1 ) ) & ~ ( type - > Align - 1 ) ;
// Enlarge this struct to enclose the new field.
2016-11-03 12:38:40 +00:00
Size = unsigned ( field - > Offset + type - > Size ) ;
2016-03-01 15:47:10 +00:00
// This struct's alignment is the same as the largest alignment of any of
// its fields.
Align = MAX ( Align , type - > Align ) ;
2017-02-07 13:48:27 +00:00
if ( Symbols . AddSymbol ( field ) = = nullptr )
2016-03-01 15:47:10 +00:00
{ // name is already in use
2017-02-08 13:34:39 +00:00
field - > Destroy ( ) ;
2017-02-07 13:48:27 +00:00
return nullptr ;
2016-03-01 15:47:10 +00:00
}
Fields . Push ( field ) ;
return field ;
}
2016-11-03 12:38:40 +00:00
//==========================================================================
//
// PStruct :: AddField
//
// Appends a new native field to the struct. Returns either the new field
2017-02-07 13:48:27 +00:00
// or nullptr if a symbol by that name already exists.
2016-11-03 12:38:40 +00:00
//
//==========================================================================
PField * PStruct : : AddNativeField ( FName name , PType * type , size_t address , DWORD flags , int bitvalue )
{
2016-11-22 18:20:31 +00:00
PField * field = new PField ( name , type , flags | VARF_Native | VARF_Transient , address , bitvalue ) ;
2016-11-03 12:38:40 +00:00
if ( Symbols . AddSymbol ( field ) = = nullptr )
{ // name is already in use
2016-11-04 14:21:45 +00:00
field - > Destroy ( ) ;
2016-11-03 12:38:40 +00:00
return nullptr ;
}
Fields . Push ( field ) ;
HasNativeFields = true ;
return field ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// NewStruct
// Returns a PStruct for the given name and container, making sure not to
// create duplicates.
//
//==========================================================================
2016-10-07 11:59:29 +00:00
PStruct * NewStruct ( FName name , PTypeBase * outer )
2016-03-01 15:47:10 +00:00
{
size_t bucket ;
2017-01-23 18:09:36 +00:00
if ( outer = = nullptr ) outer = Namespaces . GlobalNamespace ;
2016-03-01 15:47:10 +00:00
PType * stype = TypeTable . FindType ( RUNTIME_CLASS ( PStruct ) , ( intptr_t ) outer , ( intptr_t ) name , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( stype = = nullptr )
2016-03-01 15:47:10 +00:00
{
stype = new PStruct ( name , outer ) ;
TypeTable . AddType ( stype , RUNTIME_CLASS ( PStruct ) , ( intptr_t ) outer , ( intptr_t ) name , bucket ) ;
}
return static_cast < PStruct * > ( stype ) ;
}
2016-11-19 11:12:29 +00:00
/* PNativeStruct ****************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PNativeStruct , false , false )
2016-11-19 11:12:29 +00:00
//==========================================================================
//
// PNativeStruct - Parameterized Constructor
//
//==========================================================================
2017-01-23 18:09:36 +00:00
PNativeStruct : : PNativeStruct ( FName name , PTypeBase * outer )
: PStruct ( name , outer )
2016-11-19 11:12:29 +00:00
{
mDescriptiveName . Format ( " NativeStruct<%s> " , name . GetChars ( ) ) ;
Size = 0 ;
HasNativeFields = true ;
}
2016-11-21 18:20:27 +00:00
//==========================================================================
//
// NewNativeStruct
// Returns a PNativeStruct for the given name and container, making sure not to
// create duplicates.
//
//==========================================================================
PNativeStruct * NewNativeStruct ( FName name , PTypeBase * outer )
{
size_t bucket ;
2017-01-23 18:09:36 +00:00
if ( outer = = nullptr ) outer = Namespaces . GlobalNamespace ;
2016-11-21 18:20:27 +00:00
PType * stype = TypeTable . FindType ( RUNTIME_CLASS ( PNativeStruct ) , ( intptr_t ) outer , ( intptr_t ) name , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( stype = = nullptr )
2016-11-21 18:20:27 +00:00
{
2017-01-23 18:09:36 +00:00
stype = new PNativeStruct ( name , outer ) ;
2016-11-21 18:20:27 +00:00
TypeTable . AddType ( stype , RUNTIME_CLASS ( PNativeStruct ) , ( intptr_t ) outer , ( intptr_t ) name , bucket ) ;
}
return static_cast < PNativeStruct * > ( stype ) ;
}
2016-03-01 15:47:10 +00:00
/* PField *****************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PField , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PField - Default Constructor
//
//==========================================================================
PField : : PField ( )
2017-02-07 13:48:27 +00:00
: PSymbol ( NAME_None ) , Offset ( 0 ) , Type ( nullptr ) , Flags ( 0 )
2016-03-01 15:47:10 +00:00
{
}
2016-11-03 23:19:36 +00:00
2016-10-24 15:18:20 +00:00
PField : : PField ( FName name , PType * type , DWORD flags , size_t offset , int bitvalue )
2016-11-03 12:38:40 +00:00
: PSymbol ( name ) , Offset ( offset ) , Type ( type ) , Flags ( flags )
2016-10-24 15:18:20 +00:00
{
2016-11-22 18:20:31 +00:00
if ( bitvalue ! = 0 )
2016-10-24 15:18:20 +00:00
{
2016-11-03 23:19:36 +00:00
BitValue = 0 ;
unsigned val = bitvalue ;
while ( ( val > > = 1 ) ) BitValue + + ;
if ( type - > IsA ( RUNTIME_CLASS ( PInt ) ) & & unsigned ( BitValue ) < 8u * type - > Size )
2016-10-24 15:18:20 +00:00
{
// map to the single bytes in the actual variable. The internal bit instructions operate on 8 bit values.
# ifndef __BIG_ENDIAN__
Offset + = BitValue / 8 ;
# else
Offset + = type - > Size - 1 - BitValue / 8 ;
# endif
BitValue & = 7 ;
Type = TypeBool ;
}
else
{
// Just abort. Bit fields should only be defined internally.
2016-11-22 22:42:32 +00:00
I_Error ( " Trying to create an invalid bit field element: %s " , name . GetChars ( ) ) ;
2016-10-24 15:18:20 +00:00
}
}
2016-11-22 18:20:31 +00:00
else BitValue = - 1 ;
2016-10-24 15:18:20 +00:00
}
2017-01-15 15:55:30 +00:00
/* PProperty *****************************************************************/
IMPLEMENT_CLASS ( PProperty , false , false )
//==========================================================================
//
// PField - Default Constructor
//
//==========================================================================
PProperty : : PProperty ( )
: PSymbol ( NAME_None )
{
}
PProperty : : PProperty ( FName name , TArray < PField * > & fields )
: PSymbol ( name )
{
Variables = std : : move ( fields ) ;
}
2016-03-01 15:47:10 +00:00
/* PPrototype *************************************************************/
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( PPrototype , false , false )
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PPrototype - Default Constructor
//
//==========================================================================
PPrototype : : PPrototype ( )
{
}
//==========================================================================
//
// PPrototype - Parameterized Constructor
//
//==========================================================================
PPrototype : : PPrototype ( const TArray < PType * > & rettypes , const TArray < PType * > & argtypes )
: ArgumentTypes ( argtypes ) , ReturnTypes ( rettypes )
{
}
//==========================================================================
//
// PPrototype :: IsMatch
//
//==========================================================================
bool PPrototype : : IsMatch ( intptr_t id1 , intptr_t id2 ) const
{
const TArray < PType * > * args = ( const TArray < PType * > * ) id1 ;
const TArray < PType * > * rets = ( const TArray < PType * > * ) id2 ;
return * args = = ArgumentTypes & & * rets = = ReturnTypes ;
}
//==========================================================================
//
// PPrototype :: GetTypeIDs
//
//==========================================================================
void PPrototype : : GetTypeIDs ( intptr_t & id1 , intptr_t & id2 ) const
{
id1 = ( intptr_t ) & ArgumentTypes ;
id2 = ( intptr_t ) & ReturnTypes ;
}
//==========================================================================
//
// PPrototype :: PropagateMark
//
//==========================================================================
size_t PPrototype : : PropagateMark ( )
{
GC : : MarkArray ( ArgumentTypes ) ;
GC : : MarkArray ( ReturnTypes ) ;
return ( ArgumentTypes . Size ( ) + ReturnTypes . Size ( ) ) * sizeof ( void * ) +
Super : : PropagateMark ( ) ;
}
//==========================================================================
//
// NewPrototype
//
// Returns a PPrototype for the given return and argument types, making sure
// not to create duplicates.
//
//==========================================================================
PPrototype * NewPrototype ( const TArray < PType * > & rettypes , const TArray < PType * > & argtypes )
{
size_t bucket ;
PType * proto = TypeTable . FindType ( RUNTIME_CLASS ( PPrototype ) , ( intptr_t ) & argtypes , ( intptr_t ) & rettypes , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( proto = = nullptr )
2016-03-01 15:47:10 +00:00
{
proto = new PPrototype ( rettypes , argtypes ) ;
TypeTable . AddType ( proto , RUNTIME_CLASS ( PPrototype ) , ( intptr_t ) & argtypes , ( intptr_t ) & rettypes , bucket ) ;
}
return static_cast < PPrototype * > ( proto ) ;
}
/* PClass *****************************************************************/
2017-02-08 21:43:20 +00:00
IMPLEMENT_CLASS ( PClass , false , false )
2016-03-01 15:47:10 +00:00
2016-04-03 04:10:43 +00:00
//==========================================================================
//
// PClass :: WriteValue
//
// Similar to PStruct's version, except it also needs to traverse parent
// classes.
//
//==========================================================================
2016-09-20 16:27:47 +00:00
static void RecurseWriteFields ( const PClass * type , FSerializer & ar , const void * addr )
2016-04-03 04:10:43 +00:00
{
2017-02-07 13:48:27 +00:00
if ( type ! = nullptr )
2016-04-03 04:10:43 +00:00
{
RecurseWriteFields ( type - > ParentClass , ar , addr ) ;
2016-11-22 18:20:31 +00:00
// Don't write this part if it has no non-transient variables
2016-04-03 04:10:43 +00:00
for ( unsigned i = 0 ; i < type - > Fields . Size ( ) ; + + i )
{
2016-11-22 18:20:31 +00:00
if ( ! ( type - > Fields [ i ] - > Flags & VARF_Transient ) )
2016-04-03 04:10:43 +00:00
{
// Tag this section with the class it came from in case
// a more-derived class has variables that shadow a less-
// derived class. Whether or not that is a language feature
// that will actually be allowed remains to be seen.
2016-09-20 16:27:47 +00:00
FString key ;
key . Format ( " class:%s " , type - > TypeName . GetChars ( ) ) ;
if ( ar . BeginObject ( key . GetChars ( ) ) )
{
PStruct : : WriteFields ( ar , addr , type - > Fields ) ;
ar . EndObject ( ) ;
}
2016-04-03 04:10:43 +00:00
break ;
}
}
}
}
2016-09-20 16:27:47 +00:00
void PClass : : WriteValue ( FSerializer & ar , const char * key , const void * addr ) const
{
if ( ar . BeginObject ( key ) )
{
RecurseWriteFields ( this , ar , addr ) ;
ar . EndObject ( ) ;
}
}
// Same as WriteValue, but does not create a new object in the serializer
// This is so that user variables do not contain unnecessary subblocks.
void PClass : : WriteAllFields ( FSerializer & ar , const void * addr ) const
2016-04-03 04:10:43 +00:00
{
RecurseWriteFields ( this , ar , addr ) ;
}
//==========================================================================
//
// PClass :: ReadValue
//
//==========================================================================
2016-09-20 16:27:47 +00:00
bool PClass : : ReadValue ( FSerializer & ar , const char * key , void * addr ) const
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
if ( ar . BeginObject ( key ) )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
bool ret = ReadAllFields ( ar , addr ) ;
ar . EndObject ( ) ;
return ret ;
2016-04-03 04:10:43 +00:00
}
2016-09-20 16:27:47 +00:00
return true ;
}
bool PClass : : ReadAllFields ( FSerializer & ar , void * addr ) const
{
bool readsomething = false ;
bool foundsomething = false ;
const char * key ;
- removed the sequential processing of JSON objects because the benefit is too small.
After testing with a savegame on ZDCMP2 which is probably the largest map in existence, timing both methods resulted in a speed difference of less than 40 ms (70 vs 110 ms for reading all sectory, linedefs, sidedefs and objects).
This compares to an overall restoration time, including reloading the level, precaching all textures and setting everything up, of approx. 1.2 s, meaning an increase of 3% of the entire reloading time.
That's simply not worth all the negative side effects that may happen with a method that highly depends on proper code construction.
On the other hand, using random access means that a savegame version change is only needed now when the semantics of a field change, but not if some get added or deleted.
- do not I_Error out in the serializer unless caused by a programming error.
It is better to let the serializer finish, collect all the errors and I_Error out when the game is known to be in a stable enough state to allow unwinding.
2016-09-23 12:04:05 +00:00
key = ar . GetKey ( ) ;
if ( strcmp ( key , " classtype " ) )
{
// this does not represent a DObject
Printf ( TEXTCOLOR_RED " trying to read user variables but got a non-object (first key is '%s') " , key ) ;
ar . mErrors + + ;
return false ;
}
2016-09-20 16:27:47 +00:00
while ( ( key = ar . GetKey ( ) ) )
2016-04-03 04:10:43 +00:00
{
2016-09-20 16:27:47 +00:00
if ( strncmp ( key , " class: " , 6 ) )
{
- removed the sequential processing of JSON objects because the benefit is too small.
After testing with a savegame on ZDCMP2 which is probably the largest map in existence, timing both methods resulted in a speed difference of less than 40 ms (70 vs 110 ms for reading all sectory, linedefs, sidedefs and objects).
This compares to an overall restoration time, including reloading the level, precaching all textures and setting everything up, of approx. 1.2 s, meaning an increase of 3% of the entire reloading time.
That's simply not worth all the negative side effects that may happen with a method that highly depends on proper code construction.
On the other hand, using random access means that a savegame version change is only needed now when the semantics of a field change, but not if some get added or deleted.
- do not I_Error out in the serializer unless caused by a programming error.
It is better to let the serializer finish, collect all the errors and I_Error out when the game is known to be in a stable enough state to allow unwinding.
2016-09-23 12:04:05 +00:00
// We have read all user variable blocks.
2016-09-20 16:27:47 +00:00
break ;
}
foundsomething = true ;
PClass * type = PClass : : FindClass ( key + 6 ) ;
if ( type ! = nullptr )
2016-04-03 04:10:43 +00:00
{
// Only read it if the type is related to this one.
const PClass * parent ;
2017-02-07 13:48:27 +00:00
for ( parent = this ; parent ! = nullptr ; parent = parent - > ParentClass )
2016-04-03 04:10:43 +00:00
{
if ( parent = = type )
{
break ;
}
}
2016-09-20 16:27:47 +00:00
if ( parent ! = nullptr )
2016-04-03 04:10:43 +00:00
{
- removed the sequential processing of JSON objects because the benefit is too small.
After testing with a savegame on ZDCMP2 which is probably the largest map in existence, timing both methods resulted in a speed difference of less than 40 ms (70 vs 110 ms for reading all sectory, linedefs, sidedefs and objects).
This compares to an overall restoration time, including reloading the level, precaching all textures and setting everything up, of approx. 1.2 s, meaning an increase of 3% of the entire reloading time.
That's simply not worth all the negative side effects that may happen with a method that highly depends on proper code construction.
On the other hand, using random access means that a savegame version change is only needed now when the semantics of a field change, but not if some get added or deleted.
- do not I_Error out in the serializer unless caused by a programming error.
It is better to let the serializer finish, collect all the errors and I_Error out when the game is known to be in a stable enough state to allow unwinding.
2016-09-23 12:04:05 +00:00
if ( ar . BeginObject ( nullptr ) )
{
readsomething | = type - > ReadFields ( ar , addr ) ;
ar . EndObject ( ) ;
}
2016-04-03 04:10:43 +00:00
}
else
{
2016-08-28 07:55:04 +00:00
DPrintf ( DMSG_ERROR , " Unknown superclass %s of class %s \n " ,
2016-04-03 04:10:43 +00:00
type - > TypeName . GetChars ( ) , TypeName . GetChars ( ) ) ;
}
}
2016-09-20 16:27:47 +00:00
else
{
DPrintf ( DMSG_ERROR , " Unknown superclass %s of class %s \n " ,
key + 6 , TypeName . GetChars ( ) ) ;
}
2016-04-03 04:10:43 +00:00
}
2016-09-20 16:27:47 +00:00
return readsomething | | ! foundsomething ;
2016-04-03 04:10:43 +00:00
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// cregcmp
//
// Sorter to keep built-in types in a deterministic order. (Needed?)
//
//==========================================================================
2016-04-11 08:46:30 +00:00
static int cregcmp ( const void * a , const void * b ) NO_SANITIZE
2016-03-01 15:47:10 +00:00
{
const PClass * class1 = * ( const PClass * * ) a ;
const PClass * class2 = * ( const PClass * * ) b ;
return strcmp ( class1 - > TypeName , class2 - > TypeName ) ;
}
//==========================================================================
//
// PClass :: StaticInit STATIC
//
// Creates class metadata for all built-in types.
//
//==========================================================================
void PClass : : StaticInit ( )
{
atterm ( StaticShutdown ) ;
StaticBootstrap ( ) ;
2017-01-23 18:09:36 +00:00
Namespaces . GlobalNamespace = Namespaces . NewNamespace ( 0 ) ;
2016-03-01 15:47:10 +00:00
FAutoSegIterator probe ( CRegHead , CRegTail ) ;
2017-02-07 13:48:27 +00:00
while ( * + + probe ! = nullptr )
2016-03-01 15:47:10 +00:00
{
( ( ClassReg * ) * probe ) - > RegisterClass ( ) ;
}
// Keep built-in classes in consistant order. I did this before, though
// I'm not sure if this is really necessary to maintain any sort of sync.
qsort ( & AllClasses [ 0 ] , AllClasses . Size ( ) , sizeof ( AllClasses [ 0 ] ) , cregcmp ) ;
2016-10-08 20:16:10 +00:00
// Set all symbol table relations here so that they are valid right from the start.
for ( auto c : AllClasses )
{
if ( c - > ParentClass ! = nullptr )
{
c - > Symbols . SetParentTable ( & c - > ParentClass - > Symbols ) ;
}
}
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PClass :: StaticShutdown STATIC
//
2017-02-07 13:48:27 +00:00
// Frees all static class data.
2016-03-01 15:47:10 +00:00
//
//==========================================================================
void PClass : : StaticShutdown ( )
{
2017-01-31 12:41:23 +00:00
// delete all variables containing pointers to script functions.
for ( auto p : FunctionPtrList )
{
* p = nullptr ;
}
FunctionPtrList . Clear ( ) ;
2017-02-08 10:13:41 +00:00
VMFunction : : DeleteAll ( ) ;
2017-01-12 21:49:18 +00:00
2017-02-07 13:48:27 +00:00
// Make a full garbage collection here so that all destroyed but uncollected higher level objects
// that still exist are properly taken down before the low level data is deleted.
2017-01-12 21:49:18 +00:00
GC : : FullGC ( ) ;
// From this point onward no scripts may be called anymore because the data needed by the VM is getting deleted now.
// This flags DObject::Destroy not to call any scripted OnDestroy methods anymore.
2017-01-13 12:51:47 +00:00
bVMOperational = false ;
2017-01-12 21:49:18 +00:00
// Unless something went wrong, anything left here should be class and type objects only, which do not own any scripts.
2017-02-08 21:43:20 +00:00
bShutdown = true ;
2017-01-12 21:49:18 +00:00
TypeTable . Clear ( ) ;
2017-01-23 18:09:36 +00:00
Namespaces . ReleaseSymbols ( ) ;
2017-02-08 19:37:22 +00:00
ClassDataAllocator . FreeAllBlocks ( ) ;
2016-03-01 15:47:10 +00:00
AllClasses . Clear ( ) ;
PClassActor : : AllActorClasses . Clear ( ) ;
FAutoSegIterator probe ( CRegHead , CRegTail ) ;
2016-11-12 09:17:57 +00:00
while ( * + + probe ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-11-12 09:17:57 +00:00
auto cr = ( ( ClassReg * ) * probe ) ;
cr - > MyClass = nullptr ;
2016-03-01 15:47:10 +00:00
}
2017-01-12 21:49:18 +00:00
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PClass :: StaticBootstrap STATIC
//
//==========================================================================
void PClass : : StaticBootstrap ( )
{
2017-02-07 19:45:56 +00:00
PClass * cls = new PClass ;
2016-03-01 15:47:10 +00:00
PClass : : RegistrationInfo . SetupClass ( cls ) ;
2017-02-07 13:48:27 +00:00
// The PClassClass constructor initialized these to nullptr, because the
2016-03-01 15:47:10 +00:00
// PClass metadata had not been created yet. Now it has, so we know what
// they should be and can insert them into the type table successfully.
cls - > InsertIntoHash ( ) ;
// Create parent objects before we go so that these definitions are complete.
cls - > ParentClass = PClass : : RegistrationInfo . ParentType - > RegisterClass ( ) ;
}
//==========================================================================
//
// PClass Constructor
//
//==========================================================================
PClass : : PClass ( )
{
Size = sizeof ( DObject ) ;
2016-11-11 13:40:32 +00:00
ParentClass = nullptr ;
Pointers = nullptr ;
FlatPointers = nullptr ;
2017-02-07 13:48:27 +00:00
ArrayPointers = nullptr ;
2016-11-11 13:40:32 +00:00
HashNext = nullptr ;
Defaults = nullptr ;
2016-03-01 15:47:10 +00:00
bRuntimeClass = false ;
2016-10-31 16:02:47 +00:00
bExported = false ;
2016-11-13 11:02:41 +00:00
bDecorateClass = false ;
2016-11-11 13:40:32 +00:00
ConstructNative = nullptr ;
2016-10-16 17:42:22 +00:00
mDescriptiveName = " Class " ;
2016-03-01 15:47:10 +00:00
PClass : : AllClasses . Push ( this ) ;
}
//==========================================================================
//
// PClass Destructor
//
//==========================================================================
PClass : : ~ PClass ( )
{
2017-02-07 13:48:27 +00:00
if ( Defaults ! = nullptr )
2016-03-01 15:47:10 +00:00
{
M_Free ( Defaults ) ;
2017-02-07 13:48:27 +00:00
Defaults = nullptr ;
2016-03-01 15:47:10 +00:00
}
}
//==========================================================================
//
// ClassReg :: RegisterClass
//
// Create metadata describing the built-in class this struct is intended
// for.
//
//==========================================================================
PClass * ClassReg : : RegisterClass ( )
{
static ClassReg * const metaclasses [ ] =
{
& PClass : : RegistrationInfo ,
& PClassActor : : RegistrationInfo ,
} ;
// Skip classes that have already been registered
2017-02-07 13:48:27 +00:00
if ( MyClass ! = nullptr )
2016-03-01 15:47:10 +00:00
{
return MyClass ;
}
// Add type to list
PClass * cls ;
if ( MetaClassNum > = countof ( metaclasses ) )
{
assert ( 0 & & " Class registry has an invalid meta class identifier " ) ;
}
2016-11-06 10:28:01 +00:00
if ( metaclasses [ MetaClassNum ] - > MyClass = = nullptr )
2016-03-01 15:47:10 +00:00
{ // Make sure the meta class is already registered before registering this one
metaclasses [ MetaClassNum ] - > RegisterClass ( ) ;
}
cls = static_cast < PClass * > ( metaclasses [ MetaClassNum ] - > MyClass - > CreateNew ( ) ) ;
SetupClass ( cls ) ;
cls - > InsertIntoHash ( ) ;
2016-11-06 10:28:01 +00:00
if ( ParentType ! = nullptr )
2016-03-01 15:47:10 +00:00
{
cls - > ParentClass = ParentType - > RegisterClass ( ) ;
}
return cls ;
}
//==========================================================================
//
// ClassReg :: SetupClass
//
// Copies the class-defining parameters from a ClassReg to the Class object
// created for it.
//
//==========================================================================
void ClassReg : : SetupClass ( PClass * cls )
{
2017-02-07 13:48:27 +00:00
assert ( MyClass = = nullptr ) ;
2016-03-01 15:47:10 +00:00
MyClass = cls ;
cls - > TypeName = FName ( Name + 1 ) ;
cls - > Size = SizeOf ;
cls - > Pointers = Pointers ;
cls - > ConstructNative = ConstructNative ;
2016-10-16 17:42:22 +00:00
cls - > mDescriptiveName . Format ( " Class<%s> " , cls - > TypeName . GetChars ( ) ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PClass :: InsertIntoHash
//
// Add class to the type table.
//
//==========================================================================
void PClass : : InsertIntoHash ( )
{
size_t bucket ;
PType * found ;
2017-01-23 18:09:36 +00:00
found = TypeTable . FindType ( RUNTIME_CLASS ( PClass ) , 0 , TypeName , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( found ! = nullptr )
2016-03-01 15:47:10 +00:00
{ // This type has already been inserted
2016-10-07 13:28:25 +00:00
I_Error ( " Tried to register class '%s' more than once. \n " , TypeName . GetChars ( ) ) ;
2016-03-01 15:47:10 +00:00
}
else
{
2017-01-23 18:09:36 +00:00
TypeTable . AddType ( this , RUNTIME_CLASS ( PClass ) , 0 , TypeName , bucket ) ;
2016-03-01 15:47:10 +00:00
}
}
2016-04-03 04:10:43 +00:00
//==========================================================================
//
// PClass :: FindParentClass
//
// Finds a parent class that matches the given name, including itself.
//
//==========================================================================
const PClass * PClass : : FindParentClass ( FName name ) const
{
2017-02-07 13:48:27 +00:00
for ( const PClass * type = this ; type ! = nullptr ; type = type - > ParentClass )
2016-04-03 04:10:43 +00:00
{
if ( type - > TypeName = = name )
{
return type ;
}
}
2017-02-07 13:48:27 +00:00
return nullptr ;
2016-04-03 04:10:43 +00:00
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PClass :: FindClass
//
// Find a type, passed the name as a name.
//
//==========================================================================
PClass * PClass : : FindClass ( FName zaname )
{
if ( zaname = = NAME_None )
{
2017-02-07 13:48:27 +00:00
return nullptr ;
2016-03-01 15:47:10 +00:00
}
2017-02-07 13:48:27 +00:00
return static_cast < PClass * > ( TypeTable . FindType ( RUNTIME_CLASS ( PClass ) , 0 , zaname , nullptr ) ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// PClass :: CreateNew
//
// Create a new object that this class represents
//
//==========================================================================
DObject * PClass : : CreateNew ( ) const
{
BYTE * mem = ( BYTE * ) M_Malloc ( Size ) ;
2017-02-07 13:48:27 +00:00
assert ( mem ! = nullptr ) ;
2016-03-01 15:47:10 +00:00
// Set this object's defaults before constructing it.
2017-02-07 13:48:27 +00:00
if ( Defaults ! = nullptr )
2016-03-01 15:47:10 +00:00
memcpy ( mem , Defaults , Size ) ;
else
memset ( mem , 0 , Size ) ;
ConstructNative ( mem ) ;
( ( DObject * ) mem ) - > SetClass ( const_cast < PClass * > ( this ) ) ;
2017-01-15 15:55:30 +00:00
InitializeSpecials ( mem , Defaults ) ;
2016-03-01 15:47:10 +00:00
return ( DObject * ) mem ;
}
2016-04-03 22:45:04 +00:00
//==========================================================================
//
// PClass :: InitializeSpecials
//
2016-04-04 19:57:43 +00:00
// Initialize special fields (e.g. strings) of a newly-created instance.
2016-04-03 22:45:04 +00:00
//
//==========================================================================
2017-01-15 15:55:30 +00:00
void PClass : : InitializeSpecials ( void * addr , void * defaults ) const
2016-04-03 22:45:04 +00:00
{
2016-04-04 19:57:43 +00:00
// Once we reach a native class, we can stop going up the family tree,
// since native classes handle initialization natively.
if ( ! bRuntimeClass )
2016-04-03 22:45:04 +00:00
{
2016-04-04 19:57:43 +00:00
return ;
2016-04-03 22:45:04 +00:00
}
2017-02-07 13:48:27 +00:00
assert ( ParentClass ! = nullptr ) ;
2017-01-15 15:55:30 +00:00
ParentClass - > InitializeSpecials ( addr , defaults ) ;
2016-04-03 22:45:04 +00:00
for ( auto tao : SpecialInits )
{
2017-01-15 15:55:30 +00:00
tao . first - > InitializeValue ( ( char * ) addr + tao . second , defaults = = nullptr ? nullptr : ( ( char * ) defaults ) + tao . second ) ;
2016-04-03 22:45:04 +00:00
}
}
//==========================================================================
//
// PClass :: DestroySpecials
//
2016-04-04 19:57:43 +00:00
// Destroy special fields (e.g. strings) of an instance that is about to be
// deleted.
//
2016-04-03 22:45:04 +00:00
//==========================================================================
void PClass : : DestroySpecials ( void * addr ) const
{
2016-04-04 19:57:43 +00:00
// Once we reach a native class, we can stop going up the family tree,
// since native classes handle deinitialization natively.
if ( ! bRuntimeClass )
2016-04-03 22:45:04 +00:00
{
2016-04-04 19:57:43 +00:00
return ;
2016-04-03 22:45:04 +00:00
}
2017-02-07 13:48:27 +00:00
assert ( ParentClass ! = nullptr ) ;
2016-04-04 19:57:43 +00:00
ParentClass - > DestroySpecials ( addr ) ;
2016-04-03 22:45:04 +00:00
for ( auto tao : SpecialInits )
{
tao . first - > DestroyValue ( ( BYTE * ) addr + tao . second ) ;
}
}
2016-04-04 19:57:43 +00:00
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PClass :: Derive
//
// Copies inheritable values into the derived class and other miscellaneous setup.
//
//==========================================================================
2016-11-11 19:05:07 +00:00
void PClass : : Derive ( PClass * newclass , FName name )
2016-03-01 15:47:10 +00:00
{
2016-11-11 19:05:07 +00:00
newclass - > bRuntimeClass = true ;
2016-03-01 15:47:10 +00:00
newclass - > ParentClass = this ;
newclass - > ConstructNative = ConstructNative ;
2016-11-11 13:40:32 +00:00
newclass - > Symbols . SetParentTable ( & this - > Symbols ) ;
2016-11-11 19:05:07 +00:00
newclass - > TypeName = name ;
newclass - > mDescriptiveName . Format ( " Class<%s> " , name . GetChars ( ) ) ;
2016-11-11 13:40:32 +00:00
}
2016-03-01 15:47:10 +00:00
2016-11-11 13:40:32 +00:00
//==========================================================================
//
// PClassActor :: InitializeNativeDefaults
//
//==========================================================================
void PClass : : InitializeDefaults ( )
{
2017-01-29 17:23:09 +00:00
if ( IsKindOf ( RUNTIME_CLASS ( PClassActor ) ) )
{
2017-02-07 13:48:27 +00:00
assert ( Defaults = = nullptr ) ;
2017-01-29 17:23:09 +00:00
Defaults = ( BYTE * ) M_Malloc ( Size ) ;
// run the constructor on the defaults to set the vtbl pointer which is needed to run class-aware functions on them.
// Temporarily setting bSerialOverride prevents linking into the thinker chains.
auto s = DThinker : : bSerialOverride ;
DThinker : : bSerialOverride = true ;
ConstructNative ( Defaults ) ;
DThinker : : bSerialOverride = s ;
// We must unlink the defaults from the class list because it's just a static block of data to the engine.
DObject * optr = ( DObject * ) Defaults ;
GC : : Root = optr - > ObjNext ;
optr - > ObjNext = nullptr ;
optr - > SetClass ( this ) ;
// Copy the defaults from the parent but leave the DObject part alone because it contains important data.
2017-02-07 13:48:27 +00:00
if ( ParentClass - > Defaults ! = nullptr )
2016-11-11 13:40:32 +00:00
{
2017-01-29 17:23:09 +00:00
memcpy ( Defaults + sizeof ( DObject ) , ParentClass - > Defaults + sizeof ( DObject ) , ParentClass - > Size - sizeof ( DObject ) ) ;
if ( Size > ParentClass - > Size )
{
memset ( Defaults + ParentClass - > Size , 0 , Size - ParentClass - > Size ) ;
}
}
else
{
memset ( Defaults + sizeof ( DObject ) , 0 , Size - sizeof ( DObject ) ) ;
2016-11-11 13:40:32 +00:00
}
2016-03-01 15:47:10 +00:00
}
2016-11-11 13:40:32 +00:00
if ( bRuntimeClass )
{
// Copy parent values from the parent defaults.
2017-02-07 13:48:27 +00:00
assert ( ParentClass ! = nullptr ) ;
2017-01-15 15:55:30 +00:00
ParentClass - > InitializeSpecials ( Defaults , ParentClass - > Defaults ) ;
2016-11-11 13:40:32 +00:00
2016-11-17 21:21:08 +00:00
for ( const PField * field : Fields )
2016-11-11 13:40:32 +00:00
{
2016-11-17 21:21:08 +00:00
if ( ! ( field - > Flags & VARF_Native ) )
2016-11-11 13:40:32 +00:00
{
field - > Type - > SetDefaultValue ( Defaults , unsigned ( field - > Offset ) , & SpecialInits ) ;
}
}
}
2016-03-01 15:47:10 +00:00
}
2016-11-11 19:05:07 +00:00
//==========================================================================
//
// PClass :: DeriveData
//
// Copies inheritable data to the child class.
//
//==========================================================================
void PClass : : DeriveData ( PClass * newclass )
{
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PClass :: CreateDerivedClass
//
// Create a new class based on an existing class
//
//==========================================================================
PClass * PClass : : CreateDerivedClass ( FName name , unsigned int size )
{
2017-02-08 18:52:33 +00:00
assert ( size > = Size ) ;
2016-03-01 15:47:10 +00:00
PClass * type ;
bool notnew ;
2017-02-08 18:52:33 +00:00
const PClass * existclass = FindClass ( name ) ;
2016-03-01 15:47:10 +00:00
// This is a placeholder so fill it in
2017-02-08 18:52:33 +00:00
if ( existclass ! = NULL & & existclass - > Size = = ( unsigned ) - 1 )
2016-03-01 15:47:10 +00:00
{
2017-02-08 18:52:33 +00:00
type = const_cast < PClass * > ( existclass ) ;
if ( ! IsDescendantOf ( type - > ParentClass ) )
2016-03-01 15:47:10 +00:00
{
2017-02-08 18:52:33 +00:00
I_Error ( " %s must inherit from %s but doesn't. " , name . GetChars ( ) , type - > ParentClass - > TypeName . GetChars ( ) ) ;
2016-03-01 15:47:10 +00:00
}
2017-02-08 18:52:33 +00:00
DPrintf ( DMSG_SPAMMY , " Defining placeholder class %s \n " , name . GetChars ( ) ) ;
notnew = true ;
2016-03-01 15:47:10 +00:00
}
else
{
2017-02-08 18:52:33 +00:00
type = static_cast < PClass * > ( GetClass ( ) - > CreateNew ( ) ) ;
2016-03-01 15:47:10 +00:00
notnew = false ;
}
2017-02-08 18:52:33 +00:00
type - > TypeName = name ;
type - > bRuntimeClass = true ;
2016-11-11 19:05:07 +00:00
Derive ( type , name ) ;
2016-11-12 12:09:19 +00:00
type - > Size = size ;
if ( size ! = TentativeClass )
{
type - > InitializeDefaults ( ) ;
type - > Virtuals = Virtuals ;
DeriveData ( type ) ;
}
2017-02-08 18:52:33 +00:00
else
type - > ObjectFlags & = OF_Transient ;
2016-03-01 15:47:10 +00:00
if ( ! notnew )
{
type - > InsertIntoHash ( ) ;
}
return type ;
}
//==========================================================================
2016-04-03 21:18:59 +00:00
//
// PClass :: AddField
//
//==========================================================================
PField * PClass : : AddField ( FName name , PType * type , DWORD flags )
{
unsigned oldsize = Size ;
PField * field = Super : : AddField ( name , type , flags ) ;
2016-10-09 23:18:47 +00:00
// Only initialize the defaults if they have already been created.
// For ZScript this is not the case, it will first define all fields before
// setting up any defaults for any class.
if ( field ! = nullptr & & ! ( flags & VARF_Native ) & & Defaults ! = nullptr )
{
Defaults = ( BYTE * ) M_Realloc ( Defaults , Size ) ;
memset ( Defaults + oldsize , 0 , Size - oldsize ) ;
2016-04-03 21:18:59 +00:00
}
return field ;
}
//==========================================================================
2016-03-01 15:47:10 +00:00
//
// PClass :: FindClassTentative
//
// Like FindClass but creates a placeholder if no class is found.
2016-11-11 19:05:07 +00:00
// This will be filled in when the actual class is constructed.
2016-03-01 15:47:10 +00:00
//
//==========================================================================
2016-11-12 12:09:19 +00:00
PClass * PClass : : FindClassTentative ( FName name )
2016-03-01 15:47:10 +00:00
{
if ( name = = NAME_None )
{
2017-02-07 13:48:27 +00:00
return nullptr ;
2016-03-01 15:47:10 +00:00
}
size_t bucket ;
PType * found = TypeTable . FindType ( RUNTIME_CLASS ( PClass ) ,
/*FIXME:Outer*/ 0 , name , & bucket ) ;
2017-02-07 13:48:27 +00:00
if ( found ! = nullptr )
2016-03-01 15:47:10 +00:00
{
return static_cast < PClass * > ( found ) ;
}
PClass * type = static_cast < PClass * > ( GetClass ( ) - > CreateNew ( ) ) ;
2016-08-28 07:55:04 +00:00
DPrintf ( DMSG_SPAMMY , " Creating placeholder class %s : %s \n " , name . GetChars ( ) , TypeName . GetChars ( ) ) ;
2016-03-01 15:47:10 +00:00
2016-11-11 19:05:07 +00:00
Derive ( type , name ) ;
2016-03-01 15:47:10 +00:00
type - > Size = TentativeClass ;
2017-01-23 18:09:36 +00:00
TypeTable . AddType ( type , RUNTIME_CLASS ( PClass ) , 0 , name , bucket ) ;
2016-03-01 15:47:10 +00:00
return type ;
}
2016-11-11 19:05:07 +00:00
//==========================================================================
//
// PClass :: FindVirtualIndex
//
// Compares a prototype with the existing list of virtual functions
// and returns an index if something matching is found.
//
//==========================================================================
int PClass : : FindVirtualIndex ( FName name , PPrototype * proto )
{
for ( unsigned i = 0 ; i < Virtuals . Size ( ) ; i + + )
{
if ( Virtuals [ i ] - > Name = = name )
{
auto vproto = Virtuals [ i ] - > Proto ;
if ( vproto - > ReturnTypes . Size ( ) ! = proto - > ReturnTypes . Size ( ) | |
vproto - > ArgumentTypes . Size ( ) ! = proto - > ArgumentTypes . Size ( ) )
{
continue ; // number of parameters does not match, so it's incompatible
}
bool fail = false ;
// The first argument is self and will mismatch so just skip it.
for ( unsigned a = 1 ; a < proto - > ArgumentTypes . Size ( ) ; a + + )
{
if ( proto - > ArgumentTypes [ a ] ! = vproto - > ArgumentTypes [ a ] )
{
fail = true ;
break ;
}
}
if ( fail ) continue ;
for ( unsigned a = 0 ; a < proto - > ReturnTypes . Size ( ) ; a + + )
{
if ( proto - > ReturnTypes [ a ] ! = vproto - > ReturnTypes [ a ] )
{
fail = true ;
break ;
}
}
if ( ! fail ) return i ;
}
}
return - 1 ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PClass :: BuildFlatPointers
//
// Create the FlatPointers array, if it doesn't exist already.
// It comprises all the Pointers from superclasses plus this class's own
// Pointers. If this class does not define any new Pointers, then
// FlatPointers will be set to the same array as the super class.
//
//==========================================================================
void PClass : : BuildFlatPointers ( )
{
2017-02-07 13:48:27 +00:00
if ( FlatPointers ! = nullptr )
2016-03-01 15:47:10 +00:00
{ // Already built: Do nothing.
return ;
}
2017-02-07 13:48:27 +00:00
else if ( ParentClass = = nullptr )
2016-11-17 21:21:08 +00:00
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
2017-02-07 13:48:27 +00:00
if ( Pointers = = nullptr )
{ // No pointers: Make FlatPointers a harmless non-nullptr.
2016-03-01 15:47:10 +00:00
FlatPointers = & TheEnd ;
}
else
{
FlatPointers = Pointers ;
}
}
else
{
ParentClass - > BuildFlatPointers ( ) ;
2016-11-17 21:21:08 +00:00
TArray < size_t > ScriptPointers ;
// Collect all pointers in scripted fields. These are not part of the Pointers list.
for ( auto field : Fields )
{
if ( ! ( field - > Flags & VARF_Native ) )
{
field - > Type - > SetPointer ( Defaults , unsigned ( field - > Offset ) , & ScriptPointers ) ;
}
}
if ( Pointers = = nullptr & & ScriptPointers . Size ( ) = = 0 )
2016-03-01 15:47:10 +00:00
{ // No new pointers: Just use the same FlatPointers as the parent.
FlatPointers = ParentClass - > FlatPointers ;
}
else
{ // New pointers: Create a new FlatPointers array and add them.
int numPointers , numSuperPointers ;
2016-11-17 21:21:08 +00:00
if ( Pointers ! = nullptr )
{
// Count pointers defined by this class.
for ( numPointers = 0 ; Pointers [ numPointers ] ! = ~ ( size_t ) 0 ; numPointers + + )
{
}
}
else numPointers = 0 ;
2016-03-01 15:47:10 +00:00
// Count pointers defined by superclasses.
for ( numSuperPointers = 0 ; ParentClass - > FlatPointers [ numSuperPointers ] ! = ~ ( size_t ) 0 ; numSuperPointers + + )
{ }
// Concatenate them into a new array
2017-02-08 19:37:22 +00:00
size_t * flat = ( size_t * ) ClassDataAllocator . Alloc ( sizeof ( size_t ) * ( numPointers + numSuperPointers + ScriptPointers . Size ( ) + 1 ) ) ;
2016-03-01 15:47:10 +00:00
if ( numSuperPointers > 0 )
{
memcpy ( flat , ParentClass - > FlatPointers , sizeof ( size_t ) * numSuperPointers ) ;
}
2016-11-17 21:21:08 +00:00
if ( numPointers > 0 )
{
memcpy ( flat + numSuperPointers , Pointers , sizeof ( size_t ) * numPointers ) ;
}
if ( ScriptPointers . Size ( ) > 0 )
{
memcpy ( flat + numSuperPointers + numPointers , & ScriptPointers [ 0 ] , sizeof ( size_t ) * ScriptPointers . Size ( ) ) ;
}
flat [ numSuperPointers + numPointers + ScriptPointers . Size ( ) ] = ~ ( size_t ) 0 ;
2016-03-01 15:47:10 +00:00
FlatPointers = flat ;
}
}
}
2017-02-07 13:48:27 +00:00
//==========================================================================
//
// PClass :: BuildArrayPointers
//
// same as above, but creates a list to dynamic object arrays
//
//==========================================================================
void PClass : : BuildArrayPointers ( )
{
if ( ArrayPointers ! = nullptr )
{ // Already built: Do nothing.
return ;
}
else if ( ParentClass = = nullptr )
{ // No parent (i.e. DObject: FlatPointers is the same as Pointers.
ArrayPointers = & TheEnd ;
}
else
{
ParentClass - > BuildArrayPointers ( ) ;
TArray < size_t > ScriptPointers ;
// Collect all arrays to pointers in scripted fields.
for ( auto field : Fields )
{
if ( ! ( field - > Flags & VARF_Native ) )
{
field - > Type - > SetPointerArray ( Defaults , unsigned ( field - > Offset ) , & ScriptPointers ) ;
}
}
if ( ScriptPointers . Size ( ) = = 0 )
{ // No new pointers: Just use the same ArrayPointers as the parent.
ArrayPointers = ParentClass - > ArrayPointers ;
}
else
{ // New pointers: Create a new FlatPointers array and add them.
int numSuperPointers ;
// Count pointers defined by superclasses.
for ( numSuperPointers = 0 ; ParentClass - > ArrayPointers [ numSuperPointers ] ! = ~ ( size_t ) 0 ; numSuperPointers + + )
{
}
// Concatenate them into a new array
2017-02-08 19:37:22 +00:00
size_t * flat = ( size_t * ) ClassDataAllocator . Alloc ( sizeof ( size_t ) * ( numSuperPointers + ScriptPointers . Size ( ) + 1 ) ) ;
2017-02-07 13:48:27 +00:00
if ( numSuperPointers > 0 )
{
memcpy ( flat , ParentClass - > ArrayPointers , sizeof ( size_t ) * numSuperPointers ) ;
}
if ( ScriptPointers . Size ( ) > 0 )
{
memcpy ( flat + numSuperPointers , & ScriptPointers [ 0 ] , sizeof ( size_t ) * ScriptPointers . Size ( ) ) ;
}
flat [ numSuperPointers + ScriptPointers . Size ( ) ] = ~ ( size_t ) 0 ;
ArrayPointers = flat ;
}
}
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// PClass :: NativeClass
//
2016-10-08 11:34:37 +00:00
// Finds the native type underlying this class.
2016-03-01 15:47:10 +00:00
//
//==========================================================================
const PClass * PClass : : NativeClass ( ) const
{
const PClass * cls = this ;
while ( cls & & cls - > bRuntimeClass )
cls = cls - > ParentClass ;
return cls ;
}
2016-11-28 13:39:25 +00:00
VMFunction * PClass : : FindFunction ( FName clsname , FName funcname )
{
auto cls = PClass : : FindActor ( clsname ) ;
if ( ! cls ) return nullptr ;
auto func = dyn_cast < PFunction > ( cls - > Symbols . FindSymbol ( funcname , true ) ) ;
if ( ! func ) return nullptr ;
return func - > Variants [ 0 ] . Implementation ;
}
2017-01-31 12:41:23 +00:00
void PClass : : FindFunction ( VMFunction * * pptr , FName clsname , FName funcname )
{
auto cls = PClass : : FindActor ( clsname ) ;
if ( ! cls ) return ;
auto func = dyn_cast < PFunction > ( cls - > Symbols . FindSymbol ( funcname , true ) ) ;
if ( ! func ) return ;
* pptr = func - > Variants [ 0 ] . Implementation ;
FunctionPtrList . Push ( pptr ) ;
}
2016-11-28 13:39:25 +00:00
2016-03-01 15:47:10 +00:00
/* FTypeTable **************************************************************/
//==========================================================================
//
// FTypeTable :: FindType
//
//==========================================================================
PType * FTypeTable : : FindType ( PClass * metatype , intptr_t parm1 , intptr_t parm2 , size_t * bucketnum )
{
size_t bucket = Hash ( metatype , parm1 , parm2 ) % HASH_SIZE ;
2017-02-07 13:48:27 +00:00
if ( bucketnum ! = nullptr )
2016-03-01 15:47:10 +00:00
{
* bucketnum = bucket ;
}
2017-02-07 13:48:27 +00:00
for ( PType * type = TypeHash [ bucket ] ; type ! = nullptr ; type = type - > HashNext )
2016-03-01 15:47:10 +00:00
{
2017-02-07 19:25:52 +00:00
if ( type - > TypeTableType = = metatype & & type - > IsMatch ( parm1 , parm2 ) )
2016-03-01 15:47:10 +00:00
{
return type ;
}
}
2017-02-07 13:48:27 +00:00
return nullptr ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// FTypeTable :: AddType - Fully Parameterized Version
//
//==========================================================================
void FTypeTable : : AddType ( PType * type , PClass * metatype , intptr_t parm1 , intptr_t parm2 , size_t bucket )
{
# ifdef _DEBUG
size_t bucketcheck ;
2017-02-07 13:48:27 +00:00
assert ( FindType ( metatype , parm1 , parm2 , & bucketcheck ) = = nullptr & & " Type must not be inserted more than once " ) ;
2016-03-01 15:47:10 +00:00
assert ( bucketcheck = = bucket & & " Passed bucket was wrong " ) ;
# endif
2017-02-07 19:25:52 +00:00
type - > TypeTableType = metatype ;
2016-03-01 15:47:10 +00:00
type - > HashNext = TypeHash [ bucket ] ;
TypeHash [ bucket ] = type ;
2017-02-08 21:43:20 +00:00
type - > Release ( ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// FTypeTable :: AddType - Simple Version
//
//==========================================================================
void FTypeTable : : AddType ( PType * type )
{
intptr_t parm1 , parm2 ;
size_t bucket ;
2017-02-07 19:25:52 +00:00
// Type table stuff id only needed to let all classes hash to the same group. For all other types this is pointless.
type - > TypeTableType = type - > GetClass ( ) ;
PClass * metatype = type - > TypeTableType ;
2016-03-01 15:47:10 +00:00
type - > GetTypeIDs ( parm1 , parm2 ) ;
bucket = Hash ( metatype , parm1 , parm2 ) % HASH_SIZE ;
2017-02-07 13:48:27 +00:00
assert ( FindType ( metatype , parm1 , parm2 , nullptr ) = = nullptr & & " Type must not be inserted more than once " ) ;
2016-03-01 15:47:10 +00:00
type - > HashNext = TypeHash [ bucket ] ;
TypeHash [ bucket ] = type ;
2017-02-08 21:43:20 +00:00
type - > Release ( ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// FTypeTable :: Hash STATIC
//
//==========================================================================
size_t FTypeTable : : Hash ( const PClass * p1 , intptr_t p2 , intptr_t p3 )
{
size_t i1 = ( size_t ) p1 ;
// Swap the high and low halves of i1. The compiler should be smart enough
// to transform this into a ROR or ROL.
i1 = ( i1 > > ( sizeof ( size_t ) * 4 ) ) | ( i1 < < ( sizeof ( size_t ) * 4 ) ) ;
if ( p1 ! = RUNTIME_CLASS ( PPrototype ) )
{
size_t i2 = ( size_t ) p2 ;
size_t i3 = ( size_t ) p3 ;
return ( ~ i1 ^ i2 ) + i3 * 961748927 ; // i3 is multiplied by a prime
}
else
{ // Prototypes need to hash the TArrays at p2 and p3
const TArray < PType * > * a2 = ( const TArray < PType * > * ) p2 ;
const TArray < PType * > * a3 = ( const TArray < PType * > * ) p3 ;
for ( unsigned i = 0 ; i < a2 - > Size ( ) ; + + i )
{
i1 = ( i1 * 961748927 ) + ( size_t ) ( ( * a2 ) [ i ] ) ;
}
for ( unsigned i = 0 ; i < a3 - > Size ( ) ; + + i )
{
i1 = ( i1 * 961748927 ) + ( size_t ) ( ( * a3 ) [ i ] ) ;
}
return i1 ;
}
}
//==========================================================================
//
2017-02-08 21:43:20 +00:00
// FTypeTable :: Clear
2016-03-01 15:47:10 +00:00
//
//==========================================================================
2017-02-08 21:43:20 +00:00
void FTypeTable : : Clear ( )
2016-03-01 15:47:10 +00:00
{
2017-02-08 21:43:20 +00:00
for ( size_t i = 0 ; i < countof ( TypeTable . TypeHash ) ; + + i )
2016-03-01 15:47:10 +00:00
{
2017-02-08 21:43:20 +00:00
for ( PType * ty = TypeTable . TypeHash [ i ] ; ty ! = nullptr ; )
2016-03-01 15:47:10 +00:00
{
2017-02-08 21:43:20 +00:00
auto next = ty - > HashNext ;
delete ty ;
ty = next ;
2016-03-01 15:47:10 +00:00
}
}
memset ( TypeHash , 0 , sizeof ( TypeHash ) ) ;
}
# include "c_dispatch.h"
CCMD ( typetable )
{
DumpTypeTable ( ) ;
}