/*	Copyright  (c)	Günter Woigk 2010 - 2018
					mailto:kio@little-bat.de

	This file is free software

 	This program is distributed in the hope that it will be useful,
 	but WITHOUT ANY WARRANTY; without even the implied warranty of
 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

	Redistribution and use in source and binary forms, with or without
	modification, are permitted provided that the following conditions are met:

	• Redistributions of source code must retain the above copyright notice,
	  this list of conditions and the following disclaimer.
	• 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.

	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR
	CONTRIBUTORS 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 TYPE_H
#define TYPE_H


#include "Libraries/kio/kio.h"
#include "Libraries/Templates/Array.h"
#include "IdfID.h"

class Type;		  typedef const Type      cType;		typedef cType*      TypePtr;
class BasicType;  typedef const BasicType cBasicType;	typedef cBasicType* BasicTypePtr;
class ArrayType;  typedef const ArrayType cArrayType;	typedef cArrayType* ArrayTypePtr;
class PtrType;	  typedef const PtrType   cPtrType;		typedef cPtrType*   PtrTypePtr;
class EnumType;	  typedef const EnumType  cEnumType;	typedef cEnumType*  EnumTypePtr;
class StructType; typedef const StructType cStructType;	typedef cStructType*StructTypePtr;
class RangeType;  typedef const RangeType cRangeType;	typedef cRangeType* RangeTypePtr;
class ProcType;	  typedef const ProcType  cProcType;	typedef cProcType*  ProcTypePtr;
class AllocatedType;
typedef Array<cType*> Types;

//class Symbol;		typedef const Symbol cSymbol;
//class ProcSymbol;
//class TypeSymbol;
//typedef Array<Symbol> Symbols;
//typedef Array<cSymbol> cSymbols;
extern	cArrayType *tcstr;				// -> bpc


extern BasicType* newFloatType(uint bits);	// 32, 64 or 128


// ********************************************************
//		global Types: initialized by setTarget()
// ********************************************************



#define NOCOPY(T)						\
	T (T&&) = delete;					\
	T (T const&) = delete;				\
	T& operator= (T&&) = delete;		\
	T& operator= (T const&) = delete;



class Type
{
	NOCOPY(Type)

public:
	enum TypeID : uint32
	{
		VOID	= 0,

		INT 	= 8,		// flag bit
		INT8	= INT + 1,
		INT16,
		INT32,
		INT64,

		UINT	= 0x10,		// flag bit
		UINT8	= UINT + 1,
		UINT16,
		UINT32,
		UINT64,

		FLOAT	= 0x20,		// flag bit
		SFLOAT	= FLOAT + 1,
		LFLOAT	= FLOAT + 2,

		INTEGER	= INT | UINT,
		NUMERIC	= INT | UINT | FLOAT,

		ENUM	= 0x40,		// flag bit + basic type
		PTR		= 0x80,
		REF		= 0x100,
		ALL		= ENUM | REF | PTR,		// for strip()

		ALLOCATED = 0x200,
		ARRAY	= ALLOCATED + 1,
		OBJECT	= ALLOCATED + 2,

		SPECIAL	= 0x400,
		PROC,
		RANGE,
	};

	const cType* basetype;		// parent
	const cstr   name;			// short name: tUINT8, "int(bool,int)", ...
	const TypeID type;			// class identifier: VOID, ARRAY, ENUM, OBJECT, PROC, ...
	const uint	 bits;			// size is measured in bits

protected:
	mutable Types	  subtypes;	// directly derived types, e.g. int -> int&
	mutable cPtrType* ref_type;	// quick access into subtypes[]

	bool operator== (Type const&) const = delete;	// only compare by identity

	Type (cType* basetype, TypeID, cstr name, uint bits);

public:
	virtual ~Type();
	virtual void print (FD& fd, cstr indent) const;
	virtual void serialize (FD&) const throws;
	virtual void deserialize (FD&) throws;
	static Type* restore (FD&) throws;

// classification of basic types:
	bool isVoid ()			const { return type == VOID; }
	bool isNotVoid () 		const { return type != VOID; }
	bool isNumeric () 		const { return type & NUMERIC; }	// enum, uint, int or float
	bool isFloat () 		const { return type & FLOAT; }		// enum or float
	bool isInteger () 		const { return type & INTEGER; }	// enum or int
	bool isSignedInt () 	const { return type & INT; }		// enum or signed int
	bool isUnsignedInt () 	const { return type & UINT; }		// enum or uint

// derived type classes:
	bool isBasicType () 	const { return !basetype; }			// => class BasicType
	bool isEnum ()			const { return type & ENUM; }		// => class EnumType
	bool isObject () 		const { return type == OBJECT; }	// => class StructType
	bool isProcType ()		const { return type == PROC; }		// => class ProcType
	bool isArray () 		const { return type == ARRAY; } 	// => class ArrayType
	bool isString () 		const { return this == reinterpret_cast<cType*>(tcstr); } // immutable array of char
	bool isRange () 		const { return type == RANGE; }		// => class RangeType
	bool isRef () 			const { return type == REF; }		// => class PtrType
	bool isPtr () 			const { return type == PTR; }		// => class PtrType
	bool isRefToRef ()		const { return isRef() && basetype->isRef(); }
	bool isRefToPtr ()		const { return isRef() && basetype->isPtr(); }
	bool isRefToArray () 	const { return isRef() && basetype->isArray(); }
	bool isRefToAllocated() const { return isRef() && basetype->isAllocated(); }
	bool isRefOrPtr ()		const { return type & (REF|PTR); }
	bool isRefOrEnum () 	const { return type & (REF|ENUM); }
	bool isRefPtrOrEnum ()	const { return type & (ENUM|REF|PTR); }
	bool isPtrOrNum ()		const { return type & (PTR|NUMERIC); }
	bool isAllocated () 	const { return type & ALLOCATED; }
	bool isBaseTypeOf (cType* c) const { while (c && c != this) { c = c->basetype; } return c == this; }
	bool levelOfRef ()		const { return type & REF ? 1 + basetype->levelOfRef() : 0; }
	bool isArrayWithInitialCount() const;						// => class ArrayType
//	bool isSubclassed ()	const;

	virtual cType* strip (TypeID) const { return this; }
	cType*	stripEnum () 		const { return strip(ENUM); }
	cType*	stripPtr () 		const { return strip(PTR); }
	cType*	stripRef () 		const { return strip(REF); }
	cType*	stripRefOrPtr () 	const { return strip(TypeID(REF|PTR)); }
	cType*	stripRefOrEnum () 	const { return strip(TypeID(REF|ENUM)); }
	cType*	stripAll () 		const { return strip(ALL); }					// enum, ref, ptr

	cBasicType*	rootType ()		const { return basetype ? basetype->rootType() : BasicTypePtr(this); }

	cPtrType*	refSubType ()	const;
	cPtrType*	ptrSubType ()	const;
	cEnumType*	enumSubType (cstr name)	const;	// NULL if n.ex.
	cArrayType*	arraySubType (uint)	const;
	cProcType*	procSubType (Types const&)	const;
	cRangeType*	rangeSubType ()	const;


	//friend class TypeSymbol;
	//friend class ProcSymbol;

	//	union
	//	{
	//		mutable TypeSymbol*	typesymbol;		//	type's defining symbol (if any)
	//		mutable ProcSymbol*	procsymbol;		//	proc (for lvarstruct)
	//		Symbol*	mysymbol;
	//	};
	//
	//	void		setTypeSymbol (TypeSymbol*) const;
	//	void		setProcSymbol (ProcSymbol*p) const
	//	{
	//		assert(procsymbol == nullptr);
	//		procsymbol = p;
	//	}

	//cSymbols&	getMembers ()		{TODO();}
	//cSymbol*	getMember  (uint)	{TODO();}
	//uint 		structSize ()		{TODO();}
	//Symbol*		findMember (IdfID)	{TODO();}
	//Symbol*		findMember (IdfID, Type*) {TODO();}
};


// ______________________ derived types ______________________________


class BasicType : public Type	// type = tVOID, tINTEGER or tFLOAT
{
	NOCOPY(BasicType)

public:
	uint16 precision;			// fp only
	int16 min_exp;				// fp only
	int16 max_exp;				// fp only
	bool  denormalizing;		// fp only
	bool  foo;

	const float128 max;			// numeric limits
	const float128 min;			// numeric limits

public:

	BasicType (TypeID, cstr name, uint bits, float128 min, float128 max);
	BasicType (TypeID, cstr name, uint bits, float128 min, float128 max, uint16, int16, int16, bool);	// fp

	bool isInLimit (float128 n)			const noexcept { return n >= min && n <= max; }

	bool canRepresent (float128)		const noexcept;	// numeric: in limit && not denormalized
	bool isNaN (float128)				const noexcept;	// fp
	bool isInfinity (float128)			const noexcept;	// fp
	bool isDenormalized (float128)		const noexcept;	// fp
	bool isRoundToZero (float128)		const noexcept;	// fp
	uint numLostBits (float128)			const noexcept;	// fp

	void print (FD& fd, cstr indent)	const override;
	void serialize(FD&)					const override;
	void deserialize(FD&)				override;
};


// ___________________________________________________


class EnumType : public Type			// type = tENUM, basetype is a BasicType!
{
	NOCOPY(EnumType)

public:
	EnumType (cBasicType*, cstr name);

	cType* strip (TypeID mask) const	override { return mask & ENUM ? basetype : this; }
	cBasicType* basicType () const		{ return reinterpret_cast<cBasicType*>(basetype); }

	void print (FD& fd, cstr indent)	const override;
	void serialize(FD&)					const override;
	void deserialize(FD&)				override;
};


// ___________________________________________________

class PtrType : public Type				// type = tPTR or tREF
{
	NOCOPY(PtrType)

	friend class Type;
	friend class Target;
	PtrType (cType*, TypeID type);

public:

	cType* destType () const			{ return basetype; }
	cType* strip (TypeID mask) const	override { return mask & type ? basetype->strip(mask) : this; }

	void print (FD& fd, cstr indent) const override;
	void serialize(FD&) const			override;
	void deserialize(FD&)				override;
};


// ___________________________________________________

class AllocatedType : public Type	// type = tARRAY or tSTRUCT
{
	NOCOPY(AllocatedType)

protected:
	AllocatedType (cType* basetype, TypeID type, cstr name);

public:
	virtual uint allocatedSize () const = 0;	// bits
};


class ArrayType : public AllocatedType	// type = tARRAY
{										// name = "int[]"
	NOCOPY(ArrayType)					// fqn  = "int[]"

public:
	const uint initialcount;

public:
	ArrayType (cType* itemtype, uint initialcount = 0);

	cType* itemType () const			{ return basetype; }
	uint  itemSize () const				{ return basetype->bits; }						// bits
	uint  allocatedSize () const		override { return initialcount * itemSize(); }	// bits

	void  print (FD& fd, cstr indent) const override;
	void  serialize(FD&) const			override;
	void  deserialize(FD&)				override;
};




// #define DEFINE_CAST(TYPE,TEST) \
// 	inline const TYPE* TYPE ## Ptr (cType* t) { assert(t->TEST()); return static_cast<const TYPE*>(t); }
//
// DEFINE_CAST(BasicType,isBasicType)		// BasicTypePtr
// //DEFINE_CAST(ProcType,isProcType)		// ProcTypePtr
// DEFINE_CAST(ArrayType,isArray)			// ArrayTypePtr
// //DEFINE_CAST(StructType,isStruct)		// StructTypePtr
// DEFINE_CAST(AllocatedType,isAllocated)	// AllocatedTypePtr
// DEFINE_CAST(PtrType,isPtr)				// PtrTypePtr
// //DEFINE_CAST(RangeType,isRange)  		// RangeTypePtr
//
// #undef DEFINE_CAST




#if 0

class cTypes final : public RCArray<cType>
{
	int		stacksize;		// stack size [bytes]
	int		dummy;

public:
	cTypes ()							noexcept :stacksize(0){}
	cTypes (cTypes&& q)					noexcept :RCArray(std::move(q)),stacksize(q.stacksize){q.stacksize=0;}
	explicit cTypes (cTypes const& q)	:RCArray(q),stacksize(q.stacksize){}
	cTypes&	operator= (cTypes&& q)		noexcept;
	cTypes&	operator= (const cTypes& q);

	cTypes (cType* t)					:cTypes(){append(t);}
	cTypes (cType* t1, cType* t2)		:cTypes(){append(t1);append(t2);}

	static void swap (cTypes& a, cTypes& b) noexcept { RCArray::swap(a,b); std::swap(a.stacksize,b.stacksize); }


	int stackSize () const				noexcept { return stacksize; }
	//void addStackBias (int d)			noexcept { stacksize += d * Options::vstack_direction; }

	void remove (uint);
	void drop ();
	void shrink (uint newcnt);
	void purge ()						noexcept { RCArray::purge(); stacksize = 0; }
	void append (cType*);
	void append (cTypes&);

	cstr tostr (bool fullname, bool reverted) const; // arguments for printing: "(cstr, int, int)"
};


// ___________________________________________________



//#include "Options.h"
//#include "Symbol.h"


enum TypeID
{

// BasicType:

	t_int8,  t_uint8,
	t_int16, t_uint16,
	t_int32, t_uint32,
	t_int64, t_uint64,
	t_float32,
	t_float64,
	t_float128,
	//#ifdef GMP_H
	t_mpfloat,
	t_mpint,
	//#endif
	t_void,

// other sub classes:

	t_enum,
	t_proc,
	t_struct,			// allocated
	t_array,			// allocated
	t_ref,
	t_ptr,
	t_range,			// array + start + end
};

extern cstr tostr(TypeID n);	// only for BasicTypes!






// general note: order in cTypes[] is "as pushed"


class cTypes final : public RCArray<cType>
{
	int		stacksize;		// stack size [bytes]

public:
	cTypes ()							noexcept :stacksize(0){}
	cTypes (cTypes&& q)					noexcept :RCArray(q),stacksize(q.stacksize){q.stacksize=0;}
	explicit cTypes (cTypes const& q)	:RCArray(q),stacksize(q.stacksize){}

	cTypes&	operator= (cTypes&& q)		noexcept
	{
		RCArray::swap(q);
		std::swap(stacksize,q.stacksize);
		return *this;
	}
	cTypes&	operator= (const cTypes& q)
	{
		if(this != &q)
		{
			cTypes::~cTypes();
			new(this) cTypes(q);
		}
		return *this;
	}

	cTypes (cType* t)					:cTypes(){append(t);}
	cTypes (cType* t1, cType* t2)		:cTypes(){append(t1);append(t2);}

	void swap (cTypes& q)				noexcept { RCArray::swap(q); std::swap(stacksize,q.stacksize); }

	int stackSize () const				noexcept { return stacksize; }
	void addStackBias (int d)			noexcept { stacksize += d * Options::vstack_direction; }

	void remove (uint);
	void drop ();
	void shrink (uint newcnt);
	void purge ()
	{
		RCArray::purge();
		stacksize = 0;
	}
	void append (cType*);
	void append (cTypes&);

	cstr argsStr (bool fullname, bool reverted) const;	// arguments for printing:	  "(cstr, int, int)"
};


// ___________________________________________________


class Type : public RCObject
{
	friend class TypeSymbol;
	friend class ProcSymbol;

	TypeID		tid;				//	<basictype>, alias, array, struct, procptr

protected:

	cType*		basetype;			// parent
	PtrType*	ref_type;			// quick access into subtypes[]
	cTypes		subtypes;			//	directly derived types, e.g. int -> int&

	union {
		mutable TypeSymbol*	typesymbol;		//	type's defining symbol (if any)
		mutable ProcSymbol*	procsymbol;		//	proc (for lvarstruct)
		Symbol*	mysymbol;
	};

	PtrType*	addRef () const;
	EnumType*	addEnum () const;
	void		setTypeSymbol (TypeSymbol*) const;
	void		setProcSymbol (ProcSymbol*p) const
	{
		assert(procsymbol == nullptr);
		procsymbol = p;
	}

	Type (TypeID, cType* basetype);

public:
	virtual ~Type();
	Type (Type&&);
	Type& operator= (Type&&);

	cType* baseType () const		{ return basetype; }
	TypeID typeID () const			{ return tid; }
	//TypeSymbol* typeSymbol () const { assert(!mysymbol||mysymbol->isaType()); return typesymbol; }
	//ProcSymbol* procSymbol () const { assert(!mysymbol||mysymbol->isaProc()); return procsymbol; }
	cType* rootType () const		{ return basetype && tid != t_array ? basetype->rootType() : this; }
	cType* topType () const			{ return basetype ? basetype->topType() : this; }

// classification of basic types:
	bool isVoid () const			{ return tid == t_void;	}
	bool isNotVoid () const			{ return tid != t_void;	}
	bool isNumeric () const			{ return tid <= t_float128 || tid == t_enum; }
	bool isFloat () const			{ return tid == t_enum ? basetype->isFloat() : tid<=t_float128&&tid>=t_float32; }
	bool isMultiPrecision() const	{ return tid == t_mpint || t_mpfloat; }
	bool isInteger () const			{ return tid == t_enum ? basetype->isInteger() : tid <= t_uint64;}
	bool isSignedInt () const		{ return tid == t_enum ? basetype->isSignedInt() : tid <= t_int64 && ((tid&1)==0); }
	bool isUnsignedInt () const		{ return tid == t_enum ? basetype->isUnsignedInt() : tid <= t_uint64 && (tid&1); }

// derived type classes:
	bool isBasicType () const		{ return tid <= t_void; }	// => class BasicType
	bool isEnum () const			{ return tid==t_enum; }		// => class EnumType
	bool isStruct () const			{ return tid==t_struct; }	// => class StructType
	bool isProcType () const		{ return tid==t_proc; }		// => class ProcType
	bool isArray () const			{ return tid==t_array; }	// => class ArrayType
	bool isArrayWithInitialCount() const;						// => class ArrayType
	bool isString () const			{ return isArray() && basetype == static_cast<void*>(tstrchar); }
	bool isRange () const			{ return tid==t_range; }	// => class RangeType
	bool isRef () const				{ return tid==t_ref; }		// => class PtrType
	bool isPtr () const				{ return tid==t_ptr; }		// => class PtrType
	bool isRefToRef () const		{ return isRef() && basetype->isRef(); }
	bool isRefToPtr () const		{ return isRef() && basetype->isPtr(); }
	bool isRefToArray () const		{ return isRef() && basetype->isArray(); }
	bool isRefToAllocated() const	{ return isRef() && basetype->isAllocated(); }
	bool isRefOrPtr () const		{ return isRef() || isPtr(); }
	bool isRefOrEnum () const		{ return isRef() || isEnum(); }
	bool isRefPtrOrEnum () const	{ return isEnum() || isRefOrPtr(); }
	bool isPtrOrNum () const		{ return isPtr() || isNumeric(); }
	bool isAllocated () const		{ return isStruct()||isArray(); }
	bool isBaseTypeOf(cType*c)const { while(c&&c!=this) { c = c->baseType(); } return c!=nullptr; }
	bool levelOfRef () const		{ return tid==t_ref ? 1+basetype->levelOfRef() : 0;	}
	bool isSubclassed () const;

	virtual int  offsetInInt () const	{ return 0; }			// int8, int16 on 32-bit PPC system: +3 / +1
	virtual int  stackSize () const		{ return Options::bpp >> Options::b2b; } // as on stack: dflt size for pointers
	virtual int  realSize () const		{ return Options::bpp >> Options::b2b; } // as in array: dflt size for pointers
	virtual bool operator== (cType&) const;

	virtual cType* strip (StripID) const { return this; }
	cType* stripEnum () const			{ return strip(strip_enum); }
	cType* stripPtr () const			{ return strip(strip_ptr); }
	cType* stripRef () const			{ return strip(strip_ref); }
	cType* stripRefOrPtr () const		{ return strip(strip_ref_or_ptr); }
	cType* stripRefOrEnum () const		{ return strip(strip_ref_or_enum); }
	cType* stripAll () const			{ return strip(strip_all); }	// enum, ref, ptr

	virtual cType* itemType () const	{ IERR(); }					// only for array

	cSymbols&	getMembers () const;
	cSymbol*	getMember (int i) const;
	const cTypes& getSubTypes () const	{ return subtypes; }
	int 		structSize () const;
	Symbol*		findMember (IdfID i) const;
	Symbol*		findMember (IdfID i, cType*) const;

	IdfID		idf () const;
	cstr		name (bool fullname=no) const;
	cstr		FQNStr () const;			// for linker:			// e.g.: "css.foo__3intAE_4bool"
	IdfID		FQN () const;				// for linker:			// e.g.: "css.foo__3intAE_4bool"
	cstr		getDefinition (bool fullname) const;
	void		print (FD& fd, cstr indent) const;
	void		purgeSubtypes ();

	PtrType* 	ptrSubtype () const;
	PtrType*	refSubtype () const;
	ArrayType*	arraySubtype (uint) const;
	ProcType*	procSubtype (cTypes&) const;
	EnumType*	enumSubtype () const			{ assert(isBasicType()); return addEnum(); }
	RangeType*	rangeSubtype () const;
};


extern Type* uintForBits(uint bits);
extern Type* intForBits(uint bits);
extern Type* uintForBytes(uint bytes);
extern Type* intForBytes(uint bytes);


// ___________________________________________________

class ProcType : public Type		// procedure
{
public:
	cTypes	arguments;				// argument types. order: as pushed

public:
	ProcType (ProcType&& q)				:Type(std::move(q)){}
	ProcType& operator= (ProcType&& q)	{ Type::operator=(std::move(q)); return *this; }

	ProcType (cType* rtype, cTypes& arguments/*as pushed*/);
	ProcType (const ProcSymbol&);

	cstr asmArgsStr (bool fullname) const;	// arguments for asm listing: "( str, int, int -- int )"

	const cTypes& argTypes () const		{ return arguments; }			// order: as pushed
	cType*	argType (uint i) const		{ return arguments[i]; }		// order: as pushed
	int 	argCnt () const				{ return int(arguments.count()); }
	int 	argStackSize () const		{ return arguments.stackSize(); }

	cType*	returnType () const			{ return basetype; }
	bool	operator== (cType&) const	override;
};


// ___________________________________________________

class RangeType : public Type
{
public:
	RangeType (RangeType&& q)				:Type(std::move(q)){}
	RangeType& operator= (RangeType&& q)	{ Type::operator=(std::move(q)); return *this; }

	RangeType (cType*);

	ArrayType* getArrayType () const	{ return basetype->arraySubtype(0); }
	cType*	itemType () const			override { return basetype; }
	int 	stackSize () const			override { return bpr>>b2b; }	// on stack
	int 	realSize () const			override { return bpr>>b2b; }	// in array
	bool	operator== (cType&) const	override;
};


// ___________________________________________________

/*	ein StructType ist der Type zu einem Scope.
	scope(item_style)	=> struct
	scope(lvar_style)	=> lvars of proc
*/
class StructType : public AllocatedType		// { ... }
{
public:
	StructType (StructType&& q)				:AllocatedType(std::move(q)){}
	StructType& operator= (StructType&& q)	{ AllocatedType::operator=(std::move(q)); return *this; }

	StructType ( cStructType* basetype );

	cStructType* baseClass () const				{ return static_cast<cStructType*>(basetype); }
	bool	isBaseClassOf (cStructType*c) const	{ while(c&&c!=this) { c = c->baseClass(); } return c!=nullptr; }

	int 	allocatedSize () const				override { return structSize(); }
	bool	isPopulated () const				{ return structSize()>(baseClass()?baseClass()->structSize():0); }
	void	addSubtype (cStructType*);
};


// ___________________________________________________

bool Type::isArrayWithInitialCount() const
{
	return isArray() && static_cast<const ArrayType*>(this)->hasInitialCount();
}



#endif

#endif
























