ReflectionByteCodeTypes.h

// ReflectionByteCodeTypes.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2006

@import "IObject.h"

/*

A bytecode is used to represent a type together with its meta-data.  It is implicitly assumed there 
is an associated string table holding the strings, indexed with a 16 bit integer.


The following (binary) grammar describes the byte code, where

    int8        is a single byte
    int16       is a 16 bit integer formed by 2 consecutive bytes in the byte code assuming 
                little endian
    int32       is a 32 bit integer formed by 4 consecutive bytes in the byte code assuming
                little endian   
    float64     is a 64 bit double precision floating point formed by 8 consecutive bytes in 
                the byte code assuming little endian.

    meta-data:
        MDT_BOOL int8
        MDT_INT32 int32
        MDT_FLOAT64 float64
        MDT_STRING int32
        MDT_FUNCTOR_i int32 [meta-data]*i
        MDT_LIST_i          [meta-data]*i
        MDT_BEGIN_FUNCTOR int32 [meta-data]* MDT_END_FUNCTOR
        MDT_BEGIN_LIST          [meta-data]* MDT_END_LIST

    basic-type:
        FT_VOID
        FT_BOOL
        FT_INT8
        FT_INT16
        FT_INT32
        FT_INT64
        FT_INT128
        FT_UINT8
        FT_UINT16
        FT_UINT32
        FT_UINT64
        FT_UINT128
        FT_FLOAT32
        FT_FLOAT64
        FT_CHAR8
        FT_CHAR16
        FT_STRING8
        FT_STRING16

    ext-type-key:
        FT_CLASS
        FT_INTERFACE
        FT_TYPEDEF
        FT_ENUM
        FT_FUNCTOR
        FT_VARIANT
        FT_FUNCTION_PTR
        FT_NOT_REFLECTED

    unary-type-qualifier:
        FT_VOLATILE                        volatile T
        FT_CONST                           const T
        FT_ASSIGNABLE
        FT_MOVABLE
        FT_OFFSETTABLE
        FT_POINTER                         T*
        FT_REFERENCE                       T&
        FT_INTERFACE_POINTER               ptr<T>    T = interface
        FT_OPEN_VARIANT                    openvariant<T>   T = interface
        FT_PREF                            pref<T>   T = interface
        FT_CREF                            cref<T>   T = concrete class
        FT_VECTOR                          xvector<T>
        FT_DEQUE                           xdeque<T>
        FT_LIST                            xlist<T>
        FT_SET                             xset<T>
        FT_BAG                             xbag<T>
        FT_DYNARRAY                        T[]

    type:
        basic-type
        unary-type-qualifier type
        ext-type-key int16
        FT_ARRAY size type
        FT_MAP type type
        [MDT_FLAGS int32] [meta-data]* type

Note that ignoring metadata and qualifiers like FT_CONST, just after FT_CREF you always get 
FT_CLASS then a 16 bit index into the string table for the name of the class.  Just after FT_PREF 
or FT_INTERFACE_POINTER you always get FT_INTERFACE then a 16 bit index into the string table 
for the name of the interface.

    FT_CREF FT_CLASS int16
    FT_PREF FT_INTERFACE int16   
    FT_INTERFACE_POINTER FT_INTERFACE int16

Support for parameterised types
-------------------------------

We allow for parametersied types.  Parameters are identified by a zero based index
and here we designate them by T0,T1,T2,...

An example of a type parameterised in T0,T1 is

    map<T0,const T1*>
    
It is easy to represent parameterised types in byte code, by using special byte codes for
T0,T1,...

The instantiation of the parameterised type requires a context, which is basically a mapping
from the Ti to actual types.

We allow for registration of parameterised interfaces.  ReflectedInterface has a field 
for the number of template parameters.  Zero indicates it is not parameterised.
*/

namespace ceda
{

$enum+ ETypeByteCode
{
    // Simple leaf types
    FT_VOID,                    // 0x00
    FT_BOOL,                    // 0x01
    FT_INT8,                    // 0x02
    FT_INT16,                   // 0x03
    FT_INT32,                   // 0x04
    FT_INT64,                   // 0x05
    FT_INT128,                  // 0x06
    FT_UINT8,                   // 0x07
    FT_UINT16,                  // 0x08
    FT_UINT32,                  // 0x09
    FT_UINT64,                  // 0x0a
    FT_UINT128,                 // 0x0b
    FT_FLOAT32,                 // 0x0c
    FT_FLOAT64,                 // 0x0d
    FT_CHAR8,                   // 0x0e
    FT_CHAR16,                  // 0x0f
    FT_STRING8,                 // 0x10
    FT_STRING16,                // 0x11

    // Named leaf types
    FT_CLASS = 0x20,            // 0x20
    FT_INTERFACE,               // 0x21
    FT_TYPEDEF,                 // 0x22
    FT_ENUM,                    // 0x23
    FT_FUNCTOR,                 // 0x24
    FT_VARIANT,                 // 0x25
    FT_FUNCTION_PTR,            // 0x26
    FT_NOT_REFLECTED,           // 0x27
    
    // Unary qualified types
    FT_VOLATILE=0x30,           // 0x30 volatile T
    FT_CONST,                   // 0x31 const T
    FT_ASSIGNABLE,              // 0x32 causes its argument to have assignment semantics   
    FT_MOVABLE,                 // 0x33 causes it pref argument to support move semantics
    FT_OFFSETTABLE,             // 0x34 causes its argument to have offset semantics
    FT_POINTER,                 // 0x35 T*
    FT_REFERENCE,               // 0x36 T&
    
    FT_INTERFACE_POINTER=0x40,  // 0x40 ptr<T>
    FT_OPEN_VARIANT,            // 0x41 openvariant<T> 
    FT_PREF,                    // 0x42 pref<T>
    FT_CREF,                    // 0x43 cref<T>
    FT_VECTOR,                  // 0x44 xvector<T>
    FT_DEQUE,                   // 0x45 xdeque<T>
    FT_LIST,                    // 0x46 xlist<T>
    FT_SET,                     // 0x47 xset<T>
    FT_BAG,                     // 0x48 xbag<T>
    FT_DYNARRAY,                // 0x49 T[]

    FT_ARRAY=0x50,              // 0x50 T[size]
    FT_MAP,                     // 0x51 xmap<K,V>
    
    // We support 0..63 template parameters
    FT_PARAM_0 = 0x60,
    FT_PARAM_1,
    FT_PARAM_2,
    FT_PARAM_3,
    FT_PARAM_4,
    FT_PARAM_5,

    //////////////////////// Meta data ////////////////////////
    MDT_FLAGS = 0xA0,           // 0xA0
    
    MDT_BOOL,                   // 0xA1
    MDT_INT32,                  // 0xA2
    MDT_FLOAT64,                // 0xA3
    MDT_STRING,                 // 0xA4

    MDT_BEGIN_FUNCTOR,          // 0xA5
    MDT_END_FUNCTOR,            // 0xA6

    MDT_BEGIN_LIST,             // 0xA7
    MDT_END_LIST,               // 0xA8

    // We support functors with arity 0 to 31
    MDT_FUNCTOR_0 = 0xC0,
    MDT_FUNCTOR_1,
    MDT_FUNCTOR_2,
    MDT_FUNCTOR_3,
    MDT_FUNCTOR_4,
    MDT_FUNCTOR_5,

    // We supports lists with 0-31 elements
    MDT_LIST_0 = 0xE0,
    MDT_LIST_1,
    MDT_LIST_2,
    MDT_LIST_3,
    MDT_LIST_4,
    MDT_LIST_5,
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// Simple fixed size assignable types

/*
inline bool bcIsSimpleFixedSizeAssignableType(octet_t type)
{
    return FT_BOOL <= type && type <= FT_CHAR16 || type == FT_ENUM;
}
*/

///////////////////////////////////////////////////////////////////////////////////////////////////
// Simple leaf types

inline bool bcIsSignedIntegralType(octet_t type)
{
    return FT_INT8 <= type && type <= FT_INT128;
}

inline bool bcIsUnsignedIntegralType(octet_t type)
{
    return FT_UINT8 <= type && type <= FT_UINT128;
}

inline bool bcIsIntegralType(octet_t type)
{
    return FT_INT8 <= type && type <= FT_UINT128;
}

inline bool bcIsFloatType(octet_t type)
{
    return FT_FLOAT32 <= type && type <= FT_FLOAT64;
}

inline bool bcIsCharType(octet_t type)
{
    return FT_CHAR8 <= type && type <= FT_CHAR16;
}

inline bool bcIsStringType(octet_t type)
{
    return FT_STRING8 <= type && type <= FT_STRING16;
}

const ETypeByteCode bcSimpleLeafType_first = FT_VOID;
const ETypeByteCode bcSimpleLeafType_last = FT_STRING16;

inline bool bcIsSimpleLeafType(octet_t type)
{
    return bcSimpleLeafType_first <= type && type <= bcSimpleLeafType_last;
}

inline ConstStringZ bcUnqualifiedSimpleLeafTypeName(octet_t type)
{
    cxAssert(bcIsSimpleLeafType(type));
    
    static ConstStringZ names[] =
    {
        "void",
        "bool",
        "int8",
        "int16",
        "int32",
        "int64",
        "int128",
        "uint8",
        "uint16",
        "uint32",
        "uint64",
        "uint128",
        "float32",
        "float64",
        "char8",
        "char16",
        "string8",
        "string16",
    };
    return names[type-bcSimpleLeafType_first];
}

inline ConstStringZ bcQualifiedSimpleLeafTypeName(octet_t type)
{
    cxAssert(bcIsSimpleLeafType(type));
    
    static ConstStringZ names[] =
    {
        "void",
        "bool",
        "ceda::int8",
        "ceda::int16",
        "ceda::int32",
        "ceda::int64",
        "ceda::int128",
        "ceda::uint8",
        "ceda::uint16",
        "ceda::uint32",
        "ceda::uint64",
        "ceda::uint128",
        "ceda::float32",
        "ceda::float64",
        "ceda::char8",
        "ceda::char16",
        "ceda::string8",
        "ceda::string16",
    };
    return names[type-bcSimpleLeafType_first];
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Named leaf types

const ETypeByteCode bcNamedLeafType_first = FT_CLASS;
const ETypeByteCode bcNamedLeafType_last = FT_NOT_REFLECTED;

inline bool bcIsNamedLeafType(octet_t type)
{
    return bcNamedLeafType_first <= type && type <= bcNamedLeafType_last;
}

inline ConstStringZ bcNamedLeafTypeName(octet_t type)
{
    cxAssert(bcIsNamedLeafType(type));
    
    static ConstStringZ names[] =
    {
        "class",
        "interface",
        "typedef",
        "enum",
        "functor",
        "variant",
        "function",
        "?"
    };
    return names[type-bcNamedLeafType_first];
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// leaf types

const ETypeByteCode bcLeafType_first = FT_VOID;
const ETypeByteCode bcLeafType_last = FT_NOT_REFLECTED;

inline bool bcIsLeafType(octet_t type)
{
    return bcLeafType_first <= type && type <= bcLeafType_last;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Unary types that don't really change the underlying data type

inline bool bcIsAnnotationalUnaryType(octet_t type)
{
    return type == FT_VOLATILE || 
           type == FT_CONST || 
           type == FT_ASSIGNABLE ||
           type == FT_MOVABLE ||
           type == FT_OFFSETTABLE;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Unary template types

const ETypeByteCode bcUnaryTemplateType_first = FT_INTERFACE_POINTER;
const ETypeByteCode bcUnaryTemplateType_last = FT_DYNARRAY;

inline bool bcIsUnaryTemplateType(octet_t type)
{
    return bcUnaryTemplateType_first <= type && type <= bcUnaryTemplateType_last;
}

inline ConstStringZ bcUnqualifiedUnaryTemplateName(octet_t type)
{
    cxAssert(bcIsUnaryTemplateType(type));
    
    static ConstStringZ names[] =
    {
        "ptr", 
        "openvariant", 
        "pref", 
        "cref", 
        "xvector",
        "xdeque",
        "xlist",
        "xset",
        "xbag",
        "DynArray",
    };
    return names[type-bcUnaryTemplateType_first];
}

inline ConstStringZ bcQualifiedUnaryTemplateName(octet_t type)
{
    cxAssert(bcIsUnaryTemplateType(type));
    
    static ConstStringZ names[] =
    {
        "ceda::ptr",
        "ceda::openvariant",
        "ceda::pref",
        "ceda::cref",
        "ceda::xvector",
        "ceda::xdeque",
        "ceda::xlist",
        "ceda::xset",
        "ceda::xbag",
        "ceda::DynArray",
    };
    return names[type-bcUnaryTemplateType_first];
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Unary Qualifier Types

const ETypeByteCode bcUnaryQualifierType_first = FT_VOLATILE;
const ETypeByteCode bcUnaryQualifierType_last = FT_DYNARRAY;

inline bool bcIsUnaryQualifierType(octet_t type)
{
    return bcUnaryQualifierType_first <= type && type <= bcUnaryQualifierType_last;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// POD Types

// Test whether the given underlying type is a POD, where it is assumed that an FT_CLASS is not 
// a POD
inline bool bcIsPOD(octet_t type)
{
    // What about arrays?  What about functors?
    return (FT_BOOL <= type && type <= FT_CHAR16) 
        || type == FT_ENUM 
        || type == FT_POINTER 
        || type == FT_FUNCTION_PTR
        || type == FT_REFERENCE;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Type sizes

const ssize_t SIZE_OF_FUNCTOR = 2*sizeof(void*);
const ssize_t SIZE_OF_INTERFACE_PTR = 2*sizeof(void*);
const ssize_t SIZE_OF_XVECTOR = sizeof(void*)+2*sizeof(ssize_t);
const ssize_t SIZE_OF_VECTOR_MODEL = SIZE_OF_XVECTOR*2;
const ssize_t SIZE_OF_OID = 8;
const ssize_t SIZE_OF_PREF = SIZE_OF_OID + SIZE_OF_INTERFACE_PTR;
const ssize_t SIZE_OF_XMAP = SIZE_OF_PREF;
const ssize_t SIZE_OF_XSET = SIZE_OF_PREF;

inline ssize_t bcTypeSize(octet_t type)
{
    cxAssert(0 <= type && type <= FT_MAP);
    
    static const ssize_t sizes[] =
    {
        -1,                       // 0x00 void
        1,                        // 0x01 bool
        1,                        // 0x02 int8
        2,                        // 0x03 int16
        4,                        // 0x04 int32
        8,                        // 0x05 int64
        16,                       // 0x06 int128
        1,                        // 0x07 uint8
        2,                        // 0x08 uint16
        4,                        // 0x09 uint32
        8,                        // 0x0a uint64
        16,                       // 0x0b uint128
        4,                        // 0x0c float32
        8,                        // 0x0d float64
        1,                        // 0x0e char8
        2,                        // 0x0f char16
        SIZE_OF_XVECTOR,          // 0x10 string8
        SIZE_OF_XVECTOR,          // 0x11 string16
        
        -1,-1,-1,-1,-1,           // padding 0x12-0x1f
        -1,-1,-1,-1,-1,
        -1,-1,-1,-1,
        
        -1,                       // 0x20 class
        -1,                       // 0x21 interface
        -1,                       // 0x22 typedef
        4,                        // 0x23 enum
        SIZE_OF_FUNCTOR,          // 0x24 functor
        -1,                       // 0x25 variant
        sizeof(void*),            // 0x26 function ptr
        -1,                       // 0x27 not reflected

        -1,-1,-1,-1,-1,           // padding 0x28-0x2f
        -1,-1,-1,
        
        -1,                       // 0x30 volatile
        -1,                       // 0x31 const
        -1,                       // 0x32 assignable
        SIZE_OF_PREF,             // 0x33 movable
        -1,                       // 0x34 offsettable
        sizeof(void*),            // 0x35 T*
        -1,                       // 0x36 T&  

        -1,-1,-1,-1,-1,           // padding 0x37-0x3f
        -1,-1,-1,-1,
        
        SIZE_OF_INTERFACE_PTR,    // 0x40 ptr<T>
        SIZE_OF_INTERFACE_PTR,    // 0x41 openvariant<T>
        SIZE_OF_PREF,             // 0x42 pref<T>
        SIZE_OF_PREF,             // 0x43 cref<T>
        SIZE_OF_XVECTOR,          // 0x44 xvector<T>
        -1,                       // 0x45 xdeque<T> 
        -1,                       // 0x46 xlist<T>
        SIZE_OF_XSET,             // 0x47 xset<T>
        -1,                       // 0x48 xbag<T>
        SIZE_OF_XVECTOR,          // 0x49 dynarray<T>

        -1,-1,-1,-1,-1,           // padding 0x4a-0x4f
        -1,
        
        -1,                       // 0x50 T[size]
        SIZE_OF_XMAP,             // 0x51 xmap<K,V>
    };
    
    cxAssert(cxArraySize(sizes) == FT_MAP+1);
    return sizes[type];
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Metadata

inline bool bcIsMetaData(octet_t type)
{
    return type >= MDT_FLAGS;
}

enum MetaDataBitMasks
{
    MDF_READ_ONLY = 0x00000001,   // A read only field can't be edited by the user    
    MDF_INVISIBLE = 0x00000002,   // An invisible field is completely hidden from the user
    MDF_DISABLED = 0x00000004,    // A disabled field is typically grayed
    MDF_INVALID = 0x00000008,     // An invalid field is typically shown in red
    MDF_SECURE = 0x00000010,      // Used for a string that represents a password that must not be readable on the screen
    MDF_HEX = 0x00000020,         // Allows int8,int16,int32,int64 fields to be displayed in hexadecimal
};
 
} // namespace ceda