// $Header: /cvsroot/sourcenav/src/snavigator/demo/c++_demo/glish/include/Glish/Value.h,v 1.1.1.1 2002/04/18 23:35:28 mdejong Exp $

#ifndef value_h
#define value_h

#include "Glish/Dict.h"
#include "Glish/glish.h"
#include "Glish/GlishType.h"
#include "Glish/Object.h"
#include "Glish/Complex.h"

// Different types of values: constant references, references, and
// ordinary (non-indirect) values.
typedef enum { VAL_CONST, VAL_REF, VAL_VAL } value_type;

// Different types of storage for an array used to construct a Value.
typedef enum {
	COPY_ARRAY,		// copy the array
	TAKE_OVER_ARRAY,	// use the array, delete it when done with it
	PRESERVE_ARRAY		// use the array, don't delete it or grow it
	} array_storage_type;


class Value;
class Agent;
class Func;
class ArithExpr;
class RelExpr;
struct complex;
struct dcomplex;
struct record_header;	// Needed when dealing with SDS; see AddToSds()

typedef const char* charptr;
typedef Func* funcptr;
typedef Agent* agentptr;

declare(PList,Value);
typedef PList(Value) value_list;

declare(PDict,Value);
typedef PDict(Value)* recordptr;

typedef recordptr attributeptr;

typedef const Value* const_value;
declare(List,const_value);
typedef List(const_value) const_value_list;

// Classes for subvector references.
class VecRef;
#define SubVecRef(type) name2(type,SubVecRef)
class SubVecRef(glish_bool);
class SubVecRef(byte);
class SubVecRef(short);
class SubVecRef(int);
class SubVecRef(float);
class SubVecRef(double);
class SubVecRef(complex);
class SubVecRef(dcomplex);
class SubVecRef(charptr);

typedef SubVecRef(glish_bool) glish_boolref;
typedef SubVecRef(byte) byteref;
typedef SubVecRef(short) shortref;
typedef SubVecRef(int) intref;
typedef SubVecRef(float) floatref;
typedef SubVecRef(double) doubleref;
typedef SubVecRef(complex) complexref;
typedef SubVecRef(dcomplex) dcomplexref;
typedef SubVecRef(charptr) charptrref;


// Class used to differentiate integers that are SDS indices from
// just plain integers.
class SDS_Index {
public:
	SDS_Index( int ind )	{ index = ind; }
	int Index() const	{ return index; }

protected:
	int index;
	};


// Used to create lists of objects or dynamic memory that should be freed.
class DelObj;
declare(PList,DelObj);
typedef PList(DelObj) del_list;


#define copy_array(src,dest,len,type) \
	memcpy( (void*) dest, (void*) src, sizeof(type) * len )

#define copy_values(src,type) \
	copy_array( src, (void *) new type[len], length, type )

extern Value* copy_value( const Value* value );

extern const Value* false_value;
extern Value* empty_value();
extern Value* error_value();

extern Value* create_record();
extern recordptr create_record_dict();
void delete_record( recordptr r );


// The number of Value objects created and deleted.  Useful for tracking
// down inefficiencies and leaks.
extern int num_Values_created;
extern int num_Values_deleted;


class Value : public GlishObject {
public:
	Value( glish_bool value );
	Value( byte value );
	Value( short value );
	Value( int value );
	Value( float value );
	Value( double value );
	Value( complex value );
	Value( dcomplex value );
	Value( const char* value );
	Value( funcptr value );

	Value( agentptr value );

	Value( recordptr value, Agent* agent = 0 );

	Value( SDS_Index& sds_index );

	// Reference constructor.
	Value( Value* ref_value, value_type val_type );

	// Subref constructor.
	Value( Value* ref_value, int index[], int num_elements,
		value_type val_type );

	Value( glish_bool value[], int num_elements,
		array_storage_type storage = TAKE_OVER_ARRAY );
	Value( byte value[], int num_elements,
		array_storage_type storage = TAKE_OVER_ARRAY );
	Value( short value[], int num_elements,
		array_storage_type storage = TAKE_OVER_ARRAY );
	Value( int value[], int num_elements,
		array_storage_type storage = TAKE_OVER_ARRAY );
	Value( float value[], int num_elements,
		array_storage_type storage = TAKE_OVER_ARRAY );
	Value( double value[], int num_elements,
		array_storage_type storage = TAKE_OVER_ARRAY );
	Value( complex value[], int num_elements,
		array_storage_type storage = TAKE_OVER_ARRAY );
	Value( dcomplex value[], int num_elements,
		array_storage_type storage = TAKE_OVER_ARRAY );
	Value( charptr value[], int num_elements,
		array_storage_type storage = TAKE_OVER_ARRAY );
	Value( funcptr value[], int num_elements,
		array_storage_type storage = TAKE_OVER_ARRAY );

	Value( glish_boolref& value_ref );
	Value( byteref& value_ref );
	Value( shortref& value_ref );
	Value( intref& value_ref );
	Value( floatref& value_ref );
	Value( doubleref& value_ref );
	Value( complexref& value_ref );
	Value( dcomplexref& value_ref );
	Value( charptrref& value_ref );


	// Discard present value and instead take new_value.
	void TakeValue( Value* new_value );

	~Value();


	// A value manager is an object that is Unref()'d upon destruction
	// of a Value in lieu of deleting the Value's "values" member
	// variable.  Presumably the value manager knows something about
	// "values" and when deleted performs some sort of cleanup on it
	// (perhaps by deleting it, perhaps by changing its reference count,
	// perhaps by leaving it alone, etc.).
	void SetValueManager( GlishObject* manager )
		{ value_manager = manager; }


	glish_type Type() const			{ return type; }
	unsigned int Length() const
		{
		if ( Type() == TYPE_RECORD )
			return RecordPtr()->Length();
		else if ( IsRef() )
			return Deref()->Length();
		else
			return length;
		}

	// True if the value is a reference.
	int IsRef() const
		{ return type == TYPE_REF || type == TYPE_CONST; }

	// True if the value is a constant reference.
	int IsConst() const
		{ return type == TYPE_CONST; }

	// True if the value is a sub-vector reference.
	int IsVecRef() const
		{ return type == TYPE_SUBVEC_REF || type == TYPE_SUBVEC_CONST; }

	// True if the value makes sense as a numeric type (i.e.,
	// bool, integer, or floating-point).
	int IsNumeric() const;

	// True if the value is a record corresponding to a agent.
	int IsAgentRecord() const;

	// Returns the "n"'th element coereced to the corresponding type.
	glish_bool BoolVal( int n = 1 ) const;
	byte ByteVal( int n = 1 ) const;
	short ShortVal( int n = 1 ) const;
	int IntVal( int n = 1 ) const;
	float FloatVal( int n = 1 ) const;
	double DoubleVal( int n = 1 ) const;
	complex ComplexVal( int n = 1 ) const;
	dcomplex DcomplexVal( int n = 1 ) const;

	// Returns the entire value converted to a single string, with
	// "sep" used to separate array elements.  If "use_attr" is
	// true, then the value's attributes are used for determining
	// its shape (as a n-D array).
	//
	// Returns a new string, which should be delete'd when done with.
	char* StringVal( char sep = ' ', int use_attr = 0 ) const;

	// Returns the agent or function corresponding to the Value.
	Agent* AgentVal() const;
	funcptr FuncVal() const;

	// Returns the Value's SDS index, if TYPE_OPAQUE.  Returns
	// SDS_NO_SUCH_SDS if the value is not TYPE_OPAQUE.
	int SDS_IndexVal() const;


	// The following accessors return pointers to the underlying value
	// array.  The "const" versions complain with a fatal error if the
	// value is not the given type.  The non-const versions first
	// Polymorph() the values to the given type.  If called for a
	// subref, retrieves the complete underlying value, not the
	// just selected subelements.  (See the XXXRef() functions below.)
	glish_bool* BoolPtr() const;
	byte* BytePtr() const;
	short* ShortPtr() const;
	int* IntPtr() const;
	float* FloatPtr() const;
	double* DoublePtr() const;
	complex* ComplexPtr() const;
	dcomplex* DcomplexPtr() const;
	charptr* StringPtr() const;
	funcptr* FuncPtr() const;
	agentptr* AgentPtr() const;
	recordptr RecordPtr() const;

	glish_bool* BoolPtr();
	byte* BytePtr();
	short* ShortPtr();
	int* IntPtr();
	float* FloatPtr();
	double* DoublePtr();
	complex* ComplexPtr();
	dcomplex* DcomplexPtr();
	charptr* StringPtr();
	funcptr* FuncPtr();
	agentptr* AgentPtr();
	recordptr RecordPtr();

	Value* RefPtr() const		{ return (Value*) values; }

	// The following accessors are for accessing sub-array references.
	// They complain with a fatal error if the value is not a sub-array
	// reference.  Otherwise they return a reference to the underlying
	// *sub*elements. The "const" versions complain with a fatal error
	// if the value is not the given type.  The non-const versions 
	// first Polymorph() the values to the given type.
	glish_boolref& BoolRef() const;
	byteref& ByteRef() const;
	shortref& ShortRef() const;
	intref& IntRef() const;
	floatref& FloatRef() const;
	doubleref& DoubleRef() const;
	complexref& ComplexRef() const;
	dcomplexref& DcomplexRef() const;
	charptrref& StringRef() const;

	glish_boolref& BoolRef();
	byteref& ByteRef();
	shortref& ShortRef();
	intref& IntRef();
	floatref& FloatRef();
	doubleref& DoubleRef();
	complexref& ComplexRef();
	dcomplexref& DcomplexRef();
	charptrref& StringRef();

	VecRef* VecRefPtr() const	{ return (VecRef*) values; }

	// Follow the reference chain of a non-constant or constant value
	// until finding its non-reference base value.
	Value* Deref();
	const Value* Deref() const;

	Value* VecRefDeref();
	const Value* VecRefDeref() const;

	// Return a copy of the Value's contents coerced to an array
	// of the given type.  If the Value has only one element then
	// "size" copies of that element are returned (this is used
	// for promoting scalars to arrays in operations that mix
	// the two).  Otherwise, the first "size" elements are coerced
	// and returned.
	//
	// If the value cannot be coerced to the given type then a nil
	// pointer is returned.
	glish_bool* CoerceToBoolArray( int& is_copy, int size,
		glish_bool* result = 0 ) const;
	byte* CoerceToByteArray( int& is_copy, int size,
			byte* result = 0 ) const;
	short* CoerceToShortArray( int& is_copy, int size,
			short* result = 0 ) const;
	int* CoerceToIntArray( int& is_copy, int size,
			int* result = 0 ) const;
	float* CoerceToFloatArray( int& is_copy, int size,
			float* result = 0 ) const;
	double* CoerceToDoubleArray( int& is_copy, int size,
			double* result = 0 ) const;
	complex* CoerceToComplexArray( int& is_copy, int size,
			complex* result = 0 ) const;
	dcomplex* CoerceToDcomplexArray( int& is_copy, int size,
			dcomplex* result = 0 ) const;
	charptr* CoerceToStringArray( int& is_copy, int size,
			charptr* result = 0 ) const;

	// These coercions are very limited: they essentially either
	// return the corresponding xxxPtr() (if the sizes match,
	// no "result" is prespecified, and the Value is already
	// the given type) or generate a fatal error.
	funcptr* CoerceToFuncArray( int& is_copy, int size,
			funcptr* result = 0 ) const;

	// The following both return a new value.
	Value* operator[]( const Value* index ) const;
	Value* operator[]( const_value_list *index ) const;

	// Pick distinct elements from an array.
	Value* Pick( const Value* index ) const;

	// Return a reference to distinct elements from an array.
	Value* PickRef( const Value* index );

	// Assign to distinct array elements.
	void PickAssign( const Value* index, Value *value );

	// Return a true sub-array reference.
	Value* SubRef( const Value* index );
	Value* SubRef( const_value_list *args_val );

	Value* RecordRef( const Value* index ) const;	// returns a new Value

	// Returns an (unmodifiable) existing Value, or false_value if the
	// given field does not exist.
	const Value* ExistingRecordElement( const Value* index ) const;
	const Value* ExistingRecordElement( const char field[] ) const;

	// Returns a modifiable existing Value.  If the given field does
	// not exist, it is added, with an initial value of F.
	Value* GetOrCreateRecordElement( const Value* index );
	Value* GetOrCreateRecordElement( const char field[] );

	// Returns the given record element if it exists, 0 otherwise.
	// (The value must already have been tested to determine that it's
	// a record.)
	Value* HasRecordElement( const char field[] ) const;

	// Returns a modifiable existing Value, or if no field exists
	// with the given name, returns 0.
	Value* Field( const Value* index );
	Value* Field( const char field[] );

	// Returns the given field, polymorphed to the given type.
	Value* Field( const char field[], glish_type t );

	// Returns a modifiable existing Value of the nth field of a record,
	// with the first field being numbered 1.  Returns 0 if the field
	// does not exist (n is out of range) or the Value is not a record.
	Value* NthField( int n );
	const Value* NthField( int n ) const;

	// Returns a non-modifiable pointer to the nth field's name.
	// Returns 0 in the same cases as NthField does.
	const char* NthFieldName( int n ) const;

	// Returns a copy of a unique field name (one not already present)
	// for the given record, or 0 if the Value is not a record.
	//
	// The name has an embedded '*' to avoid collision with user-chosen
	// names.
	char* NewFieldName();

	// Returns a pointer to the underlying values of the given field,
	// polymorphed to the indicated type.  The length of the array is
	// returned in "len".  A nil pointer is returned the Value is not
	// a record or if it doesn't contain the given field.
	glish_bool* FieldBoolPtr( const char field[], int& len );
	byte* FieldBytePtr( const char field[], int& len );
	short* FieldShortPtr( const char field[], int& len );
	int* FieldIntPtr( const char field[], int& len );
	float* FieldFloatPtr( const char field[], int& len );
	double* FieldDoublePtr( const char field[], int& len );
	complex* FieldComplexPtr( const char field[], int& len );
	dcomplex* FieldDcomplexPtr( const char field[], int& len );
	charptr* FieldStringPtr( const char field[], int& len );

	// Looks for a field with the given name.  If present, returns true,
	// and in the second argument the scalar value corresponding to that
	// field polymorphed to the appropriate type.  If not present, returns
	// false.  The optional third argument specifies which element of a
	// multi-element value to return (not applicable when returning a
	// string).
	int FieldVal( const char field[], glish_bool& val, int n = 1 );
	int FieldVal( const char field[], byte& val, int n = 1 );
	int FieldVal( const char field[], short& val, int n = 1 );
	int FieldVal( const char field[], int& val, int n = 1 );
	int FieldVal( const char field[], float& val, int n = 1 );
	int FieldVal( const char field[], double& val, int n = 1 );
	int FieldVal( const char field[], complex& val, int n = 1 );
	int FieldVal( const char field[], dcomplex& val, int n = 1 );

	// Returns a new string in "val".
	int FieldVal( const char field[], char*& val );


	// The following SetField member functions take a field name and
	// arguments for creating a numeric or string Value.  The target
	// Value must be a record or a fatal error is generated.  A new
	// Value is constructing given the arguments and assigned to the
	// given field.

	void SetField( const char field[], glish_bool value );
	void SetField( const char field[], byte value );
	void SetField( const char field[], short value );
	void SetField( const char field[], int value );
	void SetField( const char field[], float value );
	void SetField( const char field[], double value );
	void SetField( const char field[], complex value );
	void SetField( const char field[], dcomplex value );
	void SetField( const char field[], const char* value );

	void SetField( const char field[], glish_bool value[], int num_elements,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetField( const char field[], byte value[], int num_elements,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetField( const char field[], short value[], int num_elements,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetField( const char field[], int value[], int num_elements,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetField( const char field[], float value[], int num_elements,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetField( const char field[], double value[], int num_elements,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetField( const char field[], complex value[], int num_elements,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetField( const char field[], dcomplex value[], int num_elements,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetField( const char field[], charptr value[], int num_elements,
			array_storage_type storage = TAKE_OVER_ARRAY );

	void SetField( const char field[], Value* value )
		{ AssignRecordElement( field, value ); }


	// General assignment of "this[index] = value", where "this" might
	// be a record or an array type.  Second form is for n-D arrays.
	void AssignElements( const Value* index, Value* value );
	void AssignElements( const_value_list* index, Value* value );

	// Assigns the elements of the value parameter to the corresponding 
	// elements of this.
	void AssignElements( Value* value );

	// Assigns a single record element to the given value.  Note
	// that the value may or may not wind up being copied (depending
	// on whether the record element is a reference or not).  The
	// caller should "Unref( xxx )" after the call, where "xxx"
	// is either "value" or some larger value of which "value" is
	// an element.  If AssignRecordElement needs the value to stick
	// around, it will have bumped its reference count.
	void AssignRecordElement( const char* index, Value* value );

	void Negate();	// value <- -value
	void Not();	// value <- ! value

	void ByteOpCompute( const Value* value, int lhs_len, ArithExpr* expr );
	void ShortOpCompute( const Value* value, int lhs_len, ArithExpr* expr );
	void IntOpCompute( const Value* value, int lhs_len, ArithExpr* expr );
	void FloatOpCompute( const Value* value, int lhs_len, ArithExpr* expr );
	void DoubleOpCompute( const Value* value, int lhs_len,
				ArithExpr* expr );
	void ComplexOpCompute( const Value* value, int lhs_len,
				ArithExpr* expr );
	void DcomplexOpCompute( const Value* value, int lhs_len,
				ArithExpr* expr );


	// Add the Value to the sds designated by "sds" using the given
	// name.  "dlist" is a del_list (PList of DelObj) that is used to
	// record any objects or dynamic memory required by AddToSds in order
	// to construct the SDS.  Once done with the SDS (and the SDS has
	// been destroyed), "delete_list( dlist )" should be called to
	// reclaim the memory that AddToSds needed.
	//
	// The "rh" argument is a pointer to the SDS record header
	// describing the record we're inside.  If this Value object is
	// not part of some larger record, then in the AddToSds call "rh"
	// will be nil.  But if we're part of a record, then "rh" will
	// give us a pointer to the SDS data structure corresponding to
	// that record.
	//
	// Additionally, "level" indicates how deep we are into a
	// record.  A level of 0 indicates we're at the top-level; 1
	// indicates we're dealing with a subrecord, 2 a subsubrecord,
	// etc.  We need to know this information because we do different
	// things for the cases level=0, level=1, and level=n for n > 1.
	void AddToSds( int sds, del_list* dlist, const char* name = 0,
			struct record_header* rh = 0, int level = 0 ) const;


	// Change from present type to given type.
	void Polymorph( glish_type new_type );
	void VecRefPolymorph( glish_type new_type );

	// Retrieve the non-modifiable set of attributes, possibly nil.
	const attributeptr AttributePtr() const
		{
		return attributes ? attributes->RecordPtr() : 0;
		}

	// Retrieve a modifiable, non-nil set of attributes.
	attributeptr ModAttributePtr()
		{
		InitAttributes();
		return attributes->RecordPtr();
		}

	// Retrieve a copy of a (possibly nil) attribute set.
	Value* CopyAttributePtr() const
		{
		return attributes ? copy_value( attributes ) : 0;
		}

	// Returns an (unmodifiable) existing Value, or false_value if the
	// given attribute does not exist.
	const Value* ExistingAttribute( const Value* index ) const
		{
		return attributes ?
			attributes->ExistingRecordElement( index ) :
			false_value;
		}
	const Value* ExistingAttribute( const char attribute[] ) const
		{
		return attributes ?
			attributes->ExistingRecordElement( attribute ) :
			false_value;
		}

	// Returns the given attribute if it exists, 0 otherwise.
	const Value* HasAttribute( const char attribute[] ) const
		{
                return attributes ?
			attributes->HasRecordElement( attribute ) : 0;
		}

	// Returns a new Value with the selected attributes.
	Value* AttributeRef( const Value* index ) const
		{
		return attributes ? attributes->RecordRef( index ) :
			new Value( glish_false );
		}

	// Returns a modifiable existing Value.  If the given field does
	// not exist, it is added, with an initial value of F.
	Value* GetOrCreateAttribute( const Value* index )
		{
		InitAttributes();
		return attributes->GetOrCreateRecordElement( index );
		}
	Value* GetOrCreateAttribute( const char field[] )
		{
		InitAttributes();
		return attributes->GetOrCreateRecordElement( field );
		}

	// Perform an assignment on an attribute value.
	void AssignAttribute( const char* index, Value* value )
		{
		InitAttributes();
		attributes->AssignRecordElement( index, value );
		}

	// Deletes a particular attribute. If the attribute does
	// not exist, NO action is performed.
	void DeleteAttribute( const Value* index );
	void DeleteAttribute( const char field[] );

	// Take new attributes from the given value.
	void CopyAttributes( const Value* value )
		{
		DeleteAttributes();
		attributes = value->CopyAttributePtr();
		}

	// Sets all of a Value's attributes (can be nil).
	void AssignAttributes( Value* a )
		{
		DeleteAttributes();
		attributes = a;
		}

	// Takes the attributes from a value without modifying them.
	Value* TakeAttributes()
		{
		Value* a = attributes;
		attributes = 0;
		return a;
		}

	void DescribeSelf( ostream& s ) const;

	// Provide the rudiments of copy on write... i.e. it copies
	// when necessary.
	//
	// Public to allow users to implement their own copy on write
	// until copy on write is a formal part of Glish.
	Value* CopyUnref()
		{
		if ( RefCount() == 1 )
			return this;
		else
			{
			Unref( this );	// Safe!
			Value* copy = copy_value( this );
			return copy;
			}
		}

protected:
	void SetValue( glish_bool array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( byte array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( short array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( int array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( float array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( double array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( complex array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( dcomplex array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( const char* array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( agentptr array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( funcptr array[], int len,
			array_storage_type storage = TAKE_OVER_ARRAY );
	void SetValue( recordptr value, Agent* agent );
	void SetValue( SDS_Index& array );

	void SetValue( glish_boolref& value_ref );
	void SetValue( byteref& value_ref );
	void SetValue( shortref& value_ref );
	void SetValue( intref& value_ref );
	void SetValue( floatref& value_ref );
	void SetValue( doubleref& value_ref );
	void SetValue( complexref& value_ref );
	void SetValue( dcomplexref& value_ref );
	void SetValue( charptrref& value_ref );

	void SetValue( Value *ref_value, int index[], int num_elements, 
			value_type val_type );

	virtual void SetType( glish_type new_type );

	void DeleteValue();
	void DeleteAttributes();

	void InitValue();
	void InitRecord( recordptr r, Agent* agent = 0 );

	void InitAttributes()
		{
		if ( ! attributes )
			attributes = create_record();
		}

	// Given an array index value, returns an array of integers
	// listing those elements indicated by the index.  Returns
	// nil if the index was invalid.  "num_indices" is updated
	// with the number of indices returned; "indices_are_copy"
	// indicates that the indices should be deleted once done
	// with using them.
	int* GenerateIndices( const Value* index, int& num_indices,
				int& indices_are_copy,
				int check_size = 1 ) const;

	// Return a new value holding the specified subelement(s).
	Value* ArrayRef( int* indices, int num_indices ) const;

	// Return a new value holding a reference the specified subelement(s).
	Value* TrueArrayRef( int* indices, int num_indices ) const;

	// Returns a slice of a record at the given indices.
	Value* RecordSlice( int* indices, int num_indices ) const;

	// Assign the specified subelements to copies of the corresponding
	// values.
	void AssignRecordElements( const Value* index, Value* value );
	void AssignRecordSlice( Value* value, int* indices, int num_indices );
	void AssignArrayElements( Value* value, int* indices,
					int num_indices );

	// Assigns the elements from record parameter to the corresponding 
	// elements in this object.
	void AssignRecordElements( Value* value );

	// Copies the elements from the value parameter. It assumes
	// that the sizes are compatible, and generates a warning,
	// and copies a portion otherwise.
	void AssignArrayElements( Value* value );

	// Does the actual work of assigning a list of array elements,
	// once type-checking has been done.
	void AssignArrayElements( int* indices, int num_indices,
				Value* value, int rhs_len );

	// Searches a list of indices to find the largest and returns
	// it in "max_index".  If an invalid (< 1) index is found, a
	// error is generated and false is returned; otherwise true
	// is returned.
	int IndexRange( int* indices, int num_indices, int& max_index ) const;

	char* RecordStringVal() const; // returns a new string

	// Increase array size from present value to given size.
	// If successful, true is returned.  If this can't be done for
	// our present type, an error message is generated and false is return.
	int Grow( unsigned int new_size );

	glish_type type;

	unsigned int length;
	unsigned int max_size;
	void* values;
	array_storage_type storage;
	GlishObject* value_manager;
	Value* attributes;
	};

// We couldn't do this earlier, because some of the inline definitions
// for the VecRef class depend on inline Value functions (and vice versa).

#include "VecRef.h"


extern Value* bool_rel_op_compute( const Value* lhs, const Value* rhs,
				int lhs_len, RelExpr* expr );
extern Value* byte_rel_op_compute( const Value* lhs, const Value* rhs,
				int lhs_len, RelExpr* expr );
extern Value* short_rel_op_compute( const Value* lhs, const Value* rhs,
				int lhs_len, RelExpr* expr );
extern Value* int_rel_op_compute( const Value* lhs, const Value* rhs,
				int lhs_len, RelExpr* expr );
extern Value* float_rel_op_compute( const Value* lhs, const Value* rhs,
				int lhs_len, RelExpr* expr );
extern Value* double_rel_op_compute( const Value* lhs, const Value* rhs,
				int lhs_len, RelExpr* expr );
extern Value* complex_rel_op_compute( const Value* lhs, const Value* rhs,
				int lhs_len, RelExpr* expr );
extern Value* dcomplex_rel_op_compute( const Value* lhs, const Value* rhs,
				int lhs_len, RelExpr* expr );
extern Value* string_rel_op_compute( const Value* lhs, const Value* rhs,
				int lhs_len, RelExpr* expr );

extern Value* read_value_from_SDS( int sds, int is_opaque_sds = 0 );

extern int compatible_types( const Value* v1, const Value* v2,
				glish_type& max_type );

extern void init_values();

extern void delete_list( del_list* dlist );

// The following convert a string to integer/double/dcomplex.  They
// set successful to return true if the conversion was successful,
// false if the text does not describe a valid integer/double/dcomplex.
extern int text_to_integer( const char text[], int& successful );
extern double text_to_double( const char text[], int& successful );
extern dcomplex text_to_dcomplex( const char text[], int& successful );

#endif /* value_h */
