2016-03-01 15:47:10 +00:00
/*
* * dobject . h
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 1998 - 2008 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 .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
# ifndef __DOBJECT_H__
# define __DOBJECT_H__
# include <stdlib.h>
2017-04-14 11:31:58 +00:00
# include <type_traits>
2016-03-01 15:47:10 +00:00
# include "doomtype.h"
2016-11-11 14:22:53 +00:00
# include "i_system.h"
2016-03-01 15:47:10 +00:00
class PClass ;
2017-01-15 15:55:30 +00:00
class PType ;
2016-09-18 11:26:34 +00:00
class FSerializer ;
2017-02-28 12:40:46 +00:00
class FSoundID ;
2016-03-01 15:47:10 +00:00
class DObject ;
2016-03-28 15:27:55 +00:00
/*
2016-03-01 15:47:10 +00:00
class DConsoleCommand ;
class DConsoleAlias ;
class DSeqNode ;
class DSeqActorNode ;
class DSeqPolyNode ;
class DSeqSectorNode ;
class DThinker ;
class AActor ;
class DPolyAction ;
class DMovePoly ;
class DPolyDoor ;
class DRotatePoly ;
class DPusher ;
class DScroller ;
class DSectorEffect ;
class DLighting ;
class DFireFlicker ;
class DFlicker ;
class DGlow ;
class DGlow2 ;
class DLightFlash ;
class DPhased ;
class DStrobe ;
class DMover ;
class DElevator ;
class DMovingCeiling ;
class DCeiling ;
class DDoor ;
class DMovingFloor ;
class DFloor ;
class DFloorWaggle ;
class DPlat ;
class DPillar ;
2016-03-28 15:27:55 +00:00
*/
2016-03-01 15:47:10 +00:00
class PClassActor ;
# define RUNTIME_CLASS_CASTLESS(cls) (cls::RegistrationInfo.MyClass) // Passed a native class name, returns a PClass representing that class
# define RUNTIME_CLASS(cls) ((cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // Like above, but returns the true type of the meta object
# define RUNTIME_TEMPLATE_CLASS(cls) ((typename cls::MetaClass *)RUNTIME_CLASS_CASTLESS(cls)) // RUNTIME_CLASS, but works with templated parameters on GCC
# define NATIVE_TYPE(object) (object->StaticType()) // Passed an object, returns the type of the C++ class representing the object
// Enumerations for the meta classes created by ClassReg::RegisterClass()
enum
{
CLASSREG_PClass ,
CLASSREG_PClassActor ,
} ;
struct ClassReg
{
PClass * MyClass ;
const char * Name ;
ClassReg * ParentType ;
2016-11-24 20:36:02 +00:00
ClassReg * _VMExport ;
2016-03-01 15:47:10 +00:00
const size_t * Pointers ;
void ( * ConstructNative ) ( void * ) ;
2016-11-03 23:19:36 +00:00
void ( * InitNatives ) ( ) ;
2016-03-01 15:47:10 +00:00
unsigned int SizeOf : 28 ;
unsigned int MetaClassNum : 4 ;
PClass * RegisterClass ( ) ;
void SetupClass ( PClass * cls ) ;
} ;
enum EInPlace { EC_InPlace } ;
# define DECLARE_ABSTRACT_CLASS(cls,parent) \
public : \
virtual PClass * StaticType ( ) const ; \
static ClassReg RegistrationInfo , * const RegistrationInfoPtr ; \
typedef parent Super ; \
2016-11-01 03:58:10 +00:00
private : \
2016-03-01 15:47:10 +00:00
typedef cls ThisClass ;
# define DECLARE_ABSTRACT_CLASS_WITH_META(cls,parent,meta) \
DECLARE_ABSTRACT_CLASS ( cls , parent ) \
public : \
typedef meta MetaClass ; \
MetaClass * GetClass ( ) const { return static_cast < MetaClass * > ( DObject : : GetClass ( ) ) ; } \
protected : \
enum { MetaClassNum = CLASSREG_ # # meta } ; private : \
# define DECLARE_CLASS(cls,parent) \
DECLARE_ABSTRACT_CLASS ( cls , parent ) \
private : static void InPlaceConstructor ( void * mem ) ;
# define DECLARE_CLASS_WITH_META(cls,parent,meta) \
DECLARE_ABSTRACT_CLASS_WITH_META ( cls , parent , meta ) \
private : static void InPlaceConstructor ( void * mem ) ;
# define HAS_OBJECT_POINTERS \
static const size_t PointerOffsets [ ] ;
# if defined(_MSC_VER)
# pragma section(".creg$u",read)
# define _DECLARE_TI(cls) __declspec(allocate(".creg$u")) ClassReg * const cls::RegistrationInfoPtr = &cls::RegistrationInfo;
# else
# define _DECLARE_TI(cls) ClassReg * const cls::RegistrationInfoPtr __attribute__((section(SECTION_CREG))) = &cls::RegistrationInfo;
# endif
2016-11-24 20:36:02 +00:00
# define _IMP_PCLASS(cls, ptrs, create) \
2016-03-01 15:47:10 +00:00
ClassReg cls : : RegistrationInfo = { \
2016-11-05 17:27:14 +00:00
nullptr , \
2016-03-01 15:47:10 +00:00
# cls, \
& cls : : Super : : RegistrationInfo , \
2016-11-24 20:36:02 +00:00
nullptr , \
2016-03-01 15:47:10 +00:00
ptrs , \
create , \
2016-11-24 20:36:02 +00:00
nullptr , \
2016-03-01 15:47:10 +00:00
sizeof ( cls ) , \
cls : : MetaClassNum } ; \
_DECLARE_TI ( cls ) \
PClass * cls : : StaticType ( ) const { return RegistrationInfo . MyClass ; }
2016-11-24 20:36:02 +00:00
# define IMPLEMENT_CLASS(cls, isabstract, ptrs) \
2016-11-11 14:22:53 +00:00
_X_CONSTRUCTOR_ # # isabstract ( cls ) \
2016-11-24 20:36:02 +00:00
_IMP_PCLASS ( cls , _X_POINTERS_ # # ptrs ( cls ) , _X_ABSTRACT_ # # isabstract ( cls ) )
2016-11-05 16:08:54 +00:00
2017-02-23 15:33:57 +00:00
// Taking the address of a field in an object at address > 0 instead of
2016-11-05 16:08:54 +00:00
// address 0 keeps GCC from complaining about possible misuse of offsetof.
2017-02-23 15:33:57 +00:00
// Using 8 to avoid unaligned pointer use.
2016-11-05 16:08:54 +00:00
# define IMPLEMENT_POINTERS_START(cls) const size_t cls::PointerOffsets[] = {
2017-02-23 15:33:57 +00:00
# define IMPLEMENT_POINTER(field) ((size_t)&((ThisClass*)8)->field) - 8,
2016-11-05 16:08:54 +00:00
# define IMPLEMENT_POINTERS_END ~(size_t)0 };
2016-03-01 15:47:10 +00:00
2016-11-05 17:27:14 +00:00
// Possible arguments for the IMPLEMENT_CLASS macro
# define _X_POINTERS_true(cls) cls::PointerOffsets
# define _X_POINTERS_false(cls) nullptr
2016-11-22 22:42:32 +00:00
# define _X_FIELDS_true(cls) nullptr
2016-11-05 17:27:14 +00:00
# define _X_FIELDS_false(cls) nullptr
# define _X_CONSTRUCTOR_true(cls)
# define _X_CONSTRUCTOR_false(cls) void cls::InPlaceConstructor(void *mem) { new((EInPlace *)mem) cls; }
# define _X_ABSTRACT_true(cls) nullptr
# define _X_ABSTRACT_false(cls) cls::InPlaceConstructor
2016-11-24 20:36:02 +00:00
# define _X_VMEXPORT_true(cls) nullptr
2016-11-06 10:28:01 +00:00
# define _X_VMEXPORT_false(cls) nullptr
2016-11-05 17:27:14 +00:00
2017-03-10 01:22:42 +00:00
# include "dobjgc.h"
2016-03-01 15:47:10 +00:00
class DObject
{
public :
virtual PClass * StaticType ( ) const { return RegistrationInfo . MyClass ; }
static ClassReg RegistrationInfo , * const RegistrationInfoPtr ;
static void InPlaceConstructor ( void * mem ) ;
typedef PClass MetaClass ;
private :
typedef DObject ThisClass ;
protected :
enum { MetaClassNum = CLASSREG_PClass } ;
// Per-instance variables. There are four.
2017-04-10 13:17:39 +00:00
# ifdef _DEBUG
public :
enum
{
MAGIC_ID = 0x1337cafe
} ;
uint32_t MagicID = MAGIC_ID ; // only used by the VM for checking native function parameter types.
# endif
2016-03-01 15:47:10 +00:00
private :
PClass * Class ; // This object's type
public :
DObject * ObjNext ; // Keep track of all allocated objects
DObject * GCNext ; // Next object in this collection list
2017-03-09 18:31:45 +00:00
uint32_t ObjectFlags ; // Flags for this object
2016-03-01 15:47:10 +00:00
2017-01-15 15:55:30 +00:00
void * ScriptVar ( FName field , PType * type ) ;
2017-01-17 23:11:04 +00:00
protected :
2016-03-01 15:47:10 +00:00
public :
DObject ( ) ;
DObject ( PClass * inClass ) ;
virtual ~ DObject ( ) ;
inline bool IsKindOf ( const PClass * base ) const ;
2017-02-08 14:47:22 +00:00
inline bool IsKindOf ( FName base ) const ;
2016-03-01 15:47:10 +00:00
inline bool IsA ( const PClass * type ) const ;
2016-09-18 11:26:34 +00:00
void SerializeUserVars ( FSerializer & arc ) ;
virtual void Serialize ( FSerializer & arc ) ;
2017-02-08 13:34:39 +00:00
// Releases the object from the GC, letting the caller care of any maintenance.
void Release ( ) ;
2016-03-01 15:47:10 +00:00
// For catching Serialize functions in derived classes
// that don't call their base class.
void CheckIfSerialized ( ) const ;
2017-01-12 21:49:18 +00:00
virtual void OnDestroy ( ) { }
void Destroy ( ) ;
2016-03-01 15:47:10 +00:00
2017-01-15 15:55:30 +00:00
// Add other types as needed.
2017-04-12 23:12:04 +00:00
inline bool & BoolVar ( FName field ) ;
inline int & IntVar ( FName field ) ;
inline FSoundID & SoundVar ( FName field ) ;
inline PalEntry & ColorVar ( FName field ) ;
inline FName & NameVar ( FName field ) ;
inline double & FloatVar ( FName field ) ;
inline FString & StringVar ( FName field ) ;
2017-01-18 17:46:24 +00:00
template < class T > T * & PointerVar ( FName field ) ;
2017-01-15 15:55:30 +00:00
2016-03-01 15:47:10 +00:00
// If you need to replace one object with another and want to
// change any pointers from the old object to the new object,
// use this method.
virtual size_t PointerSubstitution ( DObject * old , DObject * notOld ) ;
2016-11-30 23:05:23 +00:00
static size_t StaticPointerSubstitution ( DObject * old , DObject * notOld , bool scandefaults = false ) ;
2016-03-01 15:47:10 +00:00
PClass * GetClass ( ) const
{
2017-04-14 11:31:58 +00:00
assert ( Class ! = nullptr ) ;
2016-03-01 15:47:10 +00:00
return Class ;
}
void SetClass ( PClass * inClass )
{
Class = inClass ;
}
2017-04-14 11:31:58 +00:00
private :
struct nonew
{
} ;
void * operator new ( size_t len , nonew & )
2016-03-01 15:47:10 +00:00
{
return M_Malloc ( len ) ;
}
2017-04-14 11:31:58 +00:00
public :
void operator delete ( void * mem , nonew & )
{
M_Free ( mem ) ;
}
2016-03-01 15:47:10 +00:00
void operator delete ( void * mem )
{
M_Free ( mem ) ;
}
// GC fiddling
// An object is white if either white bit is set.
bool IsWhite ( ) const
{
return ! ! ( ObjectFlags & OF_WhiteBits ) ;
}
bool IsBlack ( ) const
{
return ! ! ( ObjectFlags & OF_Black ) ;
}
// An object is gray if it isn't white or black.
bool IsGray ( ) const
{
return ! ( ObjectFlags & OF_MarkBits ) ;
}
// An object is dead if it's the other white.
bool IsDead ( ) const
{
return ! ! ( ObjectFlags & GC : : OtherWhite ( ) & OF_WhiteBits ) ;
}
void ChangeWhite ( )
{
ObjectFlags ^ = OF_WhiteBits ;
}
void MakeWhite ( )
{
ObjectFlags = ( ObjectFlags & ~ OF_MarkBits ) | ( GC : : CurrentWhite & OF_WhiteBits ) ;
}
void White2Gray ( )
{
ObjectFlags & = ~ OF_WhiteBits ;
}
void Black2Gray ( )
{
ObjectFlags & = ~ OF_Black ;
}
void Gray2Black ( )
{
ObjectFlags | = OF_Black ;
}
// Marks all objects pointed to by this one. Returns the (approximate)
// amount of memory used by this object.
virtual size_t PropagateMark ( ) ;
protected :
// This form of placement new and delete is for use *only* by PClass's
// CreateNew() method. Do not use them for some other purpose.
void * operator new ( size_t , EInPlace * mem )
{
return ( void * ) mem ;
}
void operator delete ( void * mem , EInPlace * )
{
M_Free ( mem ) ;
}
2017-04-14 11:31:58 +00:00
template < typename T , typename . . . Args >
friend T * Create ( Args & & . . . args ) ;
2016-03-01 15:47:10 +00:00
} ;
2017-04-14 11:31:58 +00:00
template < typename T , typename . . . Args >
T * Create ( Args & & . . . args )
{
DObject : : nonew nono ;
T * object = new ( nono ) T ( std : : forward < Args > ( args ) . . . ) ;
object - > SetClass ( RUNTIME_CLASS ( T ) ) ;
assert ( object - > GetClass ( ) ! = nullptr ) ; // beware of object that get created before the type system is up.
return object ;
}
2016-11-06 23:30:26 +00:00
class AInventory ; //
2016-10-16 01:57:56 +00:00
// When you write to a pointer to an Object, you must call this for
// proper bookkeeping in case the Object holding this pointer has
// already been processed by the GC.
2016-03-01 15:47:10 +00:00
static inline void GC : : WriteBarrier ( DObject * pointing , DObject * pointed )
{
if ( pointed ! = NULL & & pointed - > IsWhite ( ) & & pointing - > IsBlack ( ) )
{
Barrier ( pointing , pointed ) ;
}
}
static inline void GC : : WriteBarrier ( DObject * pointed )
{
if ( pointed ! = NULL & & State = = GCS_Propagate & & pointed - > IsWhite ( ) )
{
Barrier ( NULL , pointed ) ;
}
}
2017-04-13 15:47:17 +00:00
# include "memarena.h"
extern FMemArena ClassDataAllocator ;
2017-02-08 12:17:25 +00:00
# include "symbols.h"
2016-03-01 15:47:10 +00:00
# include "dobjtype.h"
inline bool DObject : : IsKindOf ( const PClass * base ) const
{
return base - > IsAncestorOf ( GetClass ( ) ) ;
}
2017-02-08 14:47:22 +00:00
inline bool DObject : : IsKindOf ( FName base ) const
{
return GetClass ( ) - > IsDescendantOf ( base ) ;
}
2016-03-01 15:47:10 +00:00
inline bool DObject : : IsA ( const PClass * type ) const
{
return ( type = = GetClass ( ) ) ;
}
template < class T > T * dyn_cast ( DObject * p )
{
if ( p ! = NULL & & p - > IsKindOf ( RUNTIME_CLASS_CASTLESS ( T ) ) )
{
return static_cast < T * > ( p ) ;
}
return NULL ;
}
template < class T > const T * dyn_cast ( const DObject * p )
{
return dyn_cast < T > ( const_cast < DObject * > ( p ) ) ;
}
2017-04-12 23:12:04 +00:00
inline bool & DObject : : BoolVar ( FName field )
{
return * ( bool * ) ScriptVar ( field , nullptr ) ;
}
inline int & DObject : : IntVar ( FName field )
{
return * ( int * ) ScriptVar ( field , nullptr ) ;
}
inline FSoundID & DObject : : SoundVar ( FName field )
{
return * ( FSoundID * ) ScriptVar ( field , nullptr ) ;
}
inline PalEntry & DObject : : ColorVar ( FName field )
{
return * ( PalEntry * ) ScriptVar ( field , nullptr ) ;
}
inline FName & DObject : : NameVar ( FName field )
{
return * ( FName * ) ScriptVar ( field , nullptr ) ;
}
inline double & DObject : : FloatVar ( FName field )
{
return * ( double * ) ScriptVar ( field , nullptr ) ;
}
template < class T >
inline T * & DObject : : PointerVar ( FName field )
{
return * ( T * * ) ScriptVar ( field , nullptr ) ; // pointer check is more tricky and for the handful of uses in the DECORATE parser not worth the hassle.
}
2016-03-01 15:47:10 +00:00
# endif //__DOBJECT_H__