2019-08-23 11:56:54 -07:00
using System.Diagnostics ;
namespace System
{
struct Variant
{
2020-07-06 09:09:28 -07:00
enum ObjectType
{
UnownedObject ,
OwnedObject ,
NullObject
}
enum StructFlag
{
InternalValue ,
OwnedPtr ,
ExternalPtr
}
int mStructType ; // 0 = unowned object, 1 = owned object, 2 = null value (mData is type), otherwise is struct type (|0 is internal, |1 is owned ptr, |2 is external ptr)
2020-03-09 06:34:16 -07:00
int mData ; // This is either an Object reference, struct data, or a pointer to struct data
2019-08-23 11:56:54 -07:00
public bool OwnsMemory
{
get
{
if ( mStructType < = 2 )
return mStructType = = 1 ;
2020-07-06 09:09:28 -07:00
return ( mStructType & 1 ) ! = 0 ;
2019-08-23 11:56:54 -07:00
}
}
public bool IsObject
{
get
{
2020-07-06 09:09:28 -07:00
if ( mStructType < = 2 )
return true ;
if ( ( mStructType & 3 ) = = ( int ) StructFlag . ExternalPtr )
return VariantType . IsObject ;
return false ;
2019-08-23 11:56:54 -07:00
}
}
public Type VariantType
{
get
{
if ( mStructType = = 2 )
{
return ( Type ) Internal . UnsafeCastToObject ( ( void * ) mData ) ;
}
if ( mStructType < = 1 )
{
return Internal . UnsafeCastToObject ( ( void * ) mData ) . GetType ( ) ;
}
2020-07-06 09:09:28 -07:00
return ( Type ) Internal . UnsafeCastToObject ( ( void * ) ( mStructType & ~ 3 ) ) ;
2019-08-23 11:56:54 -07:00
}
}
public bool HasValue
{
get
{
return ( mStructType ! = 0 ) | | ( mData ! = 0 ) ;
}
}
2020-06-22 17:06:26 -07:00
public void * DataPtr
{
get mut
{
2020-07-06 09:09:28 -07:00
if ( mStructType < = 3 )
2020-06-22 17:06:26 -07:00
{
if ( mStructType = = 2 )
return null ;
Object obj = Internal . UnsafeCastToObject ( ( void * ) mData ) ;
return ( uint8 * ) Internal . UnsafeCastToPtr ( obj ) + obj . GetType ( ) . [ Friend ] mMemberDataOffset ;
}
2020-07-06 09:09:28 -07:00
if ( ( mStructType & 3 ) = = ( int ) StructFlag . InternalValue )
2020-06-22 17:06:26 -07:00
return ( void * ) & mData ;
else
return ( void * ) mData ;
}
}
2019-08-23 11:56:54 -07:00
protected override void GCMarkMembers ( )
{
2020-07-06 09:09:28 -07:00
if ( ( mStructType = = ( int ) ObjectType . UnownedObject ) | | ( mStructType = = ( int ) ObjectType . OwnedObject ) )
2019-08-23 11:56:54 -07:00
{
var obj = Internal . UnsafeCastToObject ( ( void * ) mData ) ;
GC . Mark ( obj ) ;
}
}
public void Dispose ( ) mut
{
2020-07-06 09:09:28 -07:00
if ( mStructType = = ( int ) ObjectType . OwnedObject )
2019-08-23 11:56:54 -07:00
{
delete Internal . UnsafeCastToObject ( ( void * ) mData ) ;
}
else if ( OwnsMemory )
{
delete ( void * ) mData ;
}
mStructType = 0 ;
mData = 0 ;
}
public static Variant Create < T > ( T val , bool owns = false ) where T : class
{
Variant variant ;
if ( val = = null )
{
2020-07-06 09:09:28 -07:00
variant . mStructType = ( int ) ObjectType . NullObject ;
2020-06-23 07:32:53 -07:00
variant . mData = ( int ) Internal . UnsafeCastToPtr ( typeof ( T ) ) ;
2019-08-23 11:56:54 -07:00
}
else
{
2020-07-06 09:09:28 -07:00
variant . mStructType = ( int ) ( owns ? ( int ) ObjectType . OwnedObject : ( int ) ObjectType . UnownedObject ) ;
2020-06-23 07:32:53 -07:00
variant . mData = ( int ) Internal . UnsafeCastToPtr ( val ) ;
2019-08-23 11:56:54 -07:00
}
return variant ;
}
public static Variant Create < T > ( T val ) where T : struct
{
Variant variant ;
Type type = typeof ( T ) ;
if ( sizeof ( T ) < = sizeof ( int ) )
{
2020-07-06 09:09:28 -07:00
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) ;
2019-08-23 11:56:54 -07:00
variant . mData = 0 ;
* ( T * ) & variant . mData = val ;
}
else
{
2020-07-06 09:09:28 -07:00
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) | 1 ;
2019-08-23 11:56:54 -07:00
T * newVal = ( T * ) new uint8 [ sizeof ( T ) ] * ;
* newVal = val ;
variant . mData = ( int ) ( void * ) newVal ;
}
return variant ;
}
public static Variant Create < T > ( T val ) where T : struct *
{
Variant variant ;
Type type = typeof ( T ) ;
if ( type . Size < = sizeof ( int ) )
{
2020-07-06 09:09:28 -07:00
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) ;
2019-08-23 11:56:54 -07:00
variant . mData = 0 ;
* ( T * ) & variant . mData = val ;
}
else
{
2020-07-06 09:09:28 -07:00
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) | 1 ;
2019-08-23 11:56:54 -07:00
T * newVal = ( T * ) new uint8 [ sizeof ( T ) ] * ;
* newVal = val ;
variant . mData = ( int ) ( void * ) newVal ;
}
return variant ;
}
2020-07-06 09:09:28 -07:00
public static Variant Create < T > ( ref T val ) where T : struct
{
Variant variant ;
Type type = typeof ( T ) ;
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) | 2 ;
variant . mData = 0 ;
variant . mData = ( int ) ( void * ) & val ;
return variant ;
}
public static Variant CreateOwned < T > ( T val ) where T : struct
{
Variant variant ;
Type type = typeof ( T ) ;
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) | 1 ;
T * newVal = ( T * ) new uint8 [ sizeof ( T ) ] * ;
* newVal = val ;
variant . mData = ( int ) ( void * ) newVal ;
return variant ;
}
public void EnsureReference ( ) mut
{
if ( ( mStructType < = 2 ) & & ( mStructType & 3 = = ( int ) StructFlag . InternalValue ) )
return ;
var val = mData ;
mStructType | = ( int ) StructFlag . OwnedPtr ;
int * newVal = ( int * ) new uint8 [ sizeof ( int ) ] * ;
* newVal = val ;
mData = ( int ) ( void * ) newVal ;
}
2019-08-23 11:56:54 -07:00
public static Variant Create ( Type type , void * val )
{
Variant variant ;
Debug . Assert ( ! type . IsObject ) ;
if ( type . Size < = sizeof ( int ) )
{
2020-07-06 09:09:28 -07:00
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) ;
2019-08-23 11:56:54 -07:00
variant . mData = 0 ;
2020-03-09 06:34:16 -07:00
Internal . MemCpy ( & variant . mData , val , type . [ Friend ] mSize ) ;
2019-08-23 11:56:54 -07:00
}
else
{
2020-07-06 09:09:28 -07:00
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) | 1 ;
2020-03-09 06:34:16 -07:00
void * data = new uint8 [ type . [ Friend ] mSize ] * ;
Internal . MemCpy ( data , val , type . [ Friend ] mSize ) ;
2019-08-23 11:56:54 -07:00
variant . mData = ( int ) data ;
}
return variant ;
}
2020-07-06 09:09:28 -07:00
public static Variant CreateReference ( Type type , void * val )
{
Variant variant ;
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) | 2 ;
variant . mData = ( int ) val ;
return variant ;
}
2019-08-23 11:56:54 -07:00
public static void * Alloc ( Type type , out Variant variant )
{
variant = . ( ) ;
if ( type . IsObject )
{
return & variant . mData ;
}
else
{
if ( type . Size < = sizeof ( int ) )
{
2020-07-06 09:09:28 -07:00
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) ;
2019-08-23 11:56:54 -07:00
variant . mData = 0 ;
return & variant . mData ;
}
else
{
2020-07-06 09:09:28 -07:00
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( type ) | 1 ;
2020-03-09 06:34:16 -07:00
void * data = new uint8 [ type . [ Friend ] mSize ] * ;
2019-08-23 11:56:54 -07:00
variant . mData = ( int ) data ;
return data ;
}
}
}
public T Get < T > ( ) where T : class
{
Debug . Assert ( IsObject ) ;
if ( mStructType = = 2 )
return ( T ) null ;
Type type = typeof ( T ) ;
2020-07-06 09:09:28 -07:00
T obj ;
if ( mStructType > = 3 )
obj = ( T ) Internal . UnsafeCastToObject ( * ( void * * ) ( void * ) mData ) ;
else
obj = ( T ) Internal . UnsafeCastToObject ( ( void * ) mData ) ;
2019-08-23 11:56:54 -07:00
Debug . Assert ( obj . GetType ( ) . IsSubtypeOf ( type ) ) ;
return obj ;
}
public T Get < T > ( ) where T : struct
{
Debug . Assert ( ! IsObject ) ;
2020-07-06 09:09:28 -07:00
//var type = VariantType;
2019-08-23 11:56:54 -07:00
//Debug.Assert((typeof(T) == type) || (typeof(T) == type.GetUnderlyingType()));
2020-07-06 09:09:28 -07:00
if ( ( mStructType & 3 ) = = ( int ) StructFlag . InternalValue )
2019-08-23 11:56:54 -07:00
{
int data = mData ;
return * ( T * ) & data ;
}
else
return * ( T * ) ( void * ) mData ;
}
public T Get < T > ( ) where T : struct *
{
Debug . Assert ( ! IsObject ) ;
2020-07-06 09:09:28 -07:00
//var type = VariantType;
2019-08-23 11:56:54 -07:00
//Debug.Assert((typeof(T) == type) || (typeof(T) == type.GetUnderlyingType()));
2020-07-06 09:09:28 -07:00
if ( ( mStructType & 3 ) = = ( int ) StructFlag . InternalValue )
2019-08-23 11:56:54 -07:00
{
int data = mData ;
return * ( T * ) & data ;
}
else
return * ( T * ) ( void * ) mData ;
}
2020-09-14 11:18:24 -07:00
public Result < Object > GetBoxed ( )
{
if ( IsObject )
return . Err ;
var type = VariantType ;
var boxedType = type . BoxedType ;
if ( boxedType = = null )
return . Err ;
var self = this ;
var object = Try ! ( boxedType . CreateObject ( ) ) ;
Internal . MemCpy ( ( uint8 * ) Internal . UnsafeCastToPtr ( object ) + boxedType . [ Friend ] mMemberDataOffset , self . DataPtr , type . Size ) ;
return object ;
}
2019-08-23 11:56:54 -07:00
/ * public void Get < T > ( ref T val )
{
if ( VariantType ! = typeof ( T ) )
return ;
val = Get < T > ( ) ;
} * /
public void CopyValueData ( void * dest )
{
if ( IsObject )
{
if ( mStructType = = 2 )
2020-06-22 17:06:26 -07:00
* ( ( Object * ) dest ) = null ;
else
* ( ( Object * ) dest ) = Internal . UnsafeCastToObject ( ( void * ) mData ) ;
2019-08-23 11:56:54 -07:00
return ;
}
var type = VariantType ;
2020-07-06 09:09:28 -07:00
if ( ( mStructType & 3 ) = = ( int ) StructFlag . InternalValue )
2019-08-23 11:56:54 -07:00
{
int data = mData ;
Internal . MemCpy ( dest , & data , type . Size ) ;
}
else
{
Internal . MemCpy ( dest , ( void * ) mData , type . Size ) ;
}
}
public void * GetValueData ( ) mut
{
Debug . Assert ( ! IsObject ) ;
2020-07-06 09:09:28 -07:00
if ( ( mStructType & 3 ) = = ( int ) StructFlag . InternalValue )
2019-08-23 11:56:54 -07:00
{
return ( void * ) & mData ;
}
else
{
return ( void * ) mData ;
}
}
public static bool operator = = ( Variant v1 , Variant v2 )
{
if ( v1 . IsObject )
{
if ( ! v2 . IsObject )
return false ;
if ( ( v1 . mStructType = = 2 ) ! = ( v2 . mStructType = = 2 ) )
return false ; // If one is null but the other isn't
return v1 . mData = = v2 . mData ;
}
2020-07-06 09:09:28 -07:00
if ( v1 . mStructType & 3 ! = v2 . mStructType & 3 )
2019-08-23 11:56:54 -07:00
return false ;
2020-07-06 09:09:28 -07:00
if ( ( v1 . mStructType & 3 = = 0 ) & & ( v2 . mStructType & 3 = = 0 ) )
2019-08-23 11:56:54 -07:00
return v1 . mData = = v2 . mData ;
2020-07-06 09:09:28 -07:00
var v1 ;
var v2 ;
let type = v1 . VariantType ;
let ptr1 = v1 . DataPtr ;
let ptr2 = v2 . DataPtr ;
return Internal . MemCmp ( ptr1 , ptr2 , type . [ Friend ] mSize ) = = 0 ;
2019-08-23 11:56:54 -07:00
}
public static mixin Equals < T > ( var v1 , var v2 )
{
v1 . Get < T > ( ) = = v2 . Get < T > ( )
}
2020-06-22 17:06:26 -07:00
2020-07-06 09:09:28 -07:00
public static Variant CreateFromVariant ( Variant varFrom )
2020-06-22 17:06:26 -07:00
{
Variant varTo = varFrom ;
if ( varTo . mStructType = = 1 )
varTo . mStructType = 0 ;
2020-06-23 07:32:53 -07:00
if ( varTo . mStructType > 2 )
{
2020-07-06 09:09:28 -07:00
varTo . mStructType & = ~ 3 ;
let type = ( Type ) Internal . UnsafeCastToObject ( ( void * ) ( varFrom . mStructType & ~ 3 ) ) ;
2020-06-23 07:32:53 -07:00
if ( type . [ Friend ] mSize > sizeof ( int ) )
{
2020-07-06 09:09:28 -07:00
varTo . mStructType | = ( int ) StructFlag . OwnedPtr ;
2020-06-23 07:32:53 -07:00
void * data = new uint8 [ type . [ Friend ] mSize ] * ;
Internal . MemCpy ( data , ( void * ) varFrom . mData , type . [ Friend ] mSize ) ;
varTo . mData = ( int ) data ;
}
}
2020-06-22 17:06:26 -07:00
return varTo ;
}
2020-07-06 09:09:28 -07:00
public static Variant CreateFromVariantRef ( ref Variant varFrom )
{
Variant varTo = varFrom ;
if ( varTo . mStructType = = 1 )
varTo . mStructType = 0 ;
if ( varTo . mStructType > 2 )
{
varTo . mStructType & = ~ 3 ;
varTo . mStructType | = ( int ) StructFlag . ExternalPtr ;
varTo . mData = ( int ) varFrom . DataPtr ;
}
return varTo ;
}
2020-06-23 07:32:53 -07:00
public static Result < Variant > CreateFromBoxed ( Object objectFrom )
2020-06-22 17:06:26 -07:00
{
2020-06-23 07:32:53 -07:00
if ( objectFrom = = null )
return default ;
Variant variant = ? ;
2020-06-22 17:06:26 -07:00
Type objType = objectFrom . [ Friend ] RawGetType ( ) ;
2020-06-23 07:32:53 -07:00
if ( objType . IsBoxed )
{
void * srcDataPtr = ( uint8 * ) Internal . UnsafeCastToPtr ( objectFrom ) + objType . [ Friend ] mMemberDataOffset ;
var underlying = objType . UnderlyingType ;
variant . mStructType = ( int ) Internal . UnsafeCastToPtr ( underlying ) ;
if ( underlying . Size < = sizeof ( int ) )
{
variant . mData = 0 ;
* ( int * ) & variant . mData = * ( int * ) srcDataPtr ;
}
else
{
2020-07-06 09:09:28 -07:00
variant . mStructType | = ( int ) StructFlag . OwnedPtr ;
2020-06-23 07:32:53 -07:00
void * data = new uint8 [ underlying . [ Friend ] mSize ] * ;
Internal . MemCpy ( data , srcDataPtr , underlying . [ Friend ] mSize ) ;
variant . mData = ( int ) data ;
}
}
else
{
variant . mStructType = 0 ;
variant . mData = ( int ) Internal . UnsafeCastToPtr ( objectFrom ) ;
}
return variant ;
}
2019-08-23 11:56:54 -07:00
}
}