implementation module StdDynamicLowLevelInterface;

import StdEnv;
// low-level interface for dynamics
import StdDynamicVersion;
//import DebugUtilities;
import BitSet;
import StdDynamicDefaultElem;
import StdMaybe;
//from type_io_read import instance DefaultElem Maybe;

F a b :== b;

// General
make_start_node_index :== (0 bitor 3);

is_external_entry_node node_index :== ((node_index bitand 3) <> 3);

// Deconstructors for a NodeIndex (external references)
get_block_i		node_index :== ((node_index bitand 0x0000ffff) >> 2);
get_en_node_i	node_index :== (node_index >> 16);

// internal references; is_internal_reference and DYNAMIC_CONTAINS_BLOCKTABLE *must* hold
get_offset_from_internal_reference	internal_reference :== internal_reference >> 2;

// dereference an internal reference to the offset realtive from block start
dereference_internal_reference offset_of_reference internal_reference
	:== offset_of_reference - (get_offset_from_internal_reference internal_reference);

// Deconstructors for a prefix_set_and_string_ptr
is_reference prefix_set_and_desc_ptr				:== (is_internal_reference	prefix_set_and_desc_ptr) || (is_external_reference	prefix_set_and_desc_ptr);
is_internal_reference	prefix_set_and_desc_ptr		:== prefix_set_and_desc_ptr bitand 3 == 1;
is_external_reference	prefix_set_and_desc_ptr		:== prefix_set_and_desc_ptr bitand 3 == 3;

get_encoded_descriptor prefix_set_and_desc_ptr	:== get_string_offset prefix_set_and_desc_ptr;

// to be applied after get_encoded_descriptor
is_boxed encoded_descP :== encoded_descP == 0;

// to be applied after get_encoded_descriptor and is_boxed must be false
convert_to_descriptor_usage_entry encoded_descP :== convert_to_descriptor_usage_entry encoded_descP
where {
	convert_to_descriptor_usage_entry encoded_descP
		| is_boxed encoded_descP
			= abort "convert_to_descriptor_usage_entry: internal error";
		= (encoded_descP - 4) >> 2;
};

// obsolete ...
get_string_offset	prefix_set_and_string_ptr	:== prefix_set_and_string_ptr bitand 0x00ffffff;
// ... obsolete
get_prefix_set		prefix_set_and_string_ptr	:== (prefix_set_and_string_ptr >> 24)  bitand 0x000000ff;		

// To be used on result of (get_prefix_set prefix_set_and_string_ptr) application
get_n_prefix	prefix_set	:==	prefix_set bitand 1;
get_d_prefix	prefix_set	:== prefix_set bitand 2;
get_k_prefix	prefix_set 	:== prefix_set bitand 4;
get_c_prefix	prefix_set	:== prefix_set bitand 8;
get_t_prefix	prefix_set	:== prefix_set bitand 16;
get_r_prefix	prefix_set	:== prefix_set bitand 32;

is_record		prefix_set	:== (get_r_prefix prefix_set <> 0); // || (get_k_prefix prefix_set <> 0);

// To be used on result of (get_?_prefix prefix_set)
to_char_prefix :: !Int -> !Char;
to_char_prefix 1	= 'n';
to_char_prefix 2	= 'd';
to_char_prefix 4	= 'k'; 
to_char_prefix 8	= 'c'; 
to_char_prefix 16	= 't'; 
to_char_prefix 32	= 'r'; 

// Order is important because in case of a labelname more than one used prefix, the offsets in
// the encoded graph are encoded in the order below. Should be tested.
GET_PREFIX_FUNC :== [get_r_prefix,get_t_prefix,get_c_prefix,get_k_prefix,get_d_prefix,get_n_prefix];

DATA_PREFIXES	:== ['r','t','k','d'];

// Header
:: DynamicHeader = {
	// required
		header_size			:: !Int			// size in bytes
	,	version_number		:: !Int			// version number representation
	,	graph_i				:: !Int			
	,	graph_s				:: !Int	
// NEW ...
	,	block_table_i		:: !Int
	,	block_table_s		:: !Int
	,	dynamic_rts_info_i	:: !Int
	,	dynamic_rts_info_s	:: !Int
// ... NEW		
	,	stringtable_i		:: !Int			
	,	stringtable_s		:: !Int
	,	descriptortable_i	:: !Int
	,	descriptortable_s	:: !Int
	,	n_nodes				:: !Int
	
	};

default_dynamic_header :: !DynamicHeader;
default_dynamic_header	
	= { DynamicHeader |
	// required
		header_size			= 0		
	,	version_number		= 0			
	,	graph_i				= 0			
	,	graph_s				= 0	
// NEW ...
	,	block_table_i		= 0
	,	block_table_s		= 0
	,	dynamic_rts_info_i	= 0
	,	dynamic_rts_info_s	= 0
// ... NEW				
	,	stringtable_i		= 0		
	,	stringtable_s		= 0
	,	descriptortable_i	= 0
	,	descriptortable_s	= 0
	,	n_nodes				= 0
	
	};
	
N_DUMMY_BYTES_BEFORE_DYNAMIC_HEADER		:== 0;
	
class BinaryDynamicIO m
where {
	bd_readi :: !*m -> (!Bool,!Int,!*m);
	bd_reads :: !*m !Int -> (!*{#Char},!*m);
	bd_seek :: !*m !Int !Int -> (!Bool,!*m);
	bd_delta_fp :: !*m -> (!Int,!*m);
	bd_freadsubstring :: !Int !Int !*{#Char} !*m -> (!Int,!*{#Char},!*m)
};

instance BinaryDynamicIO File
where {
	bd_readi file		= freadi file;
	bd_reads file i		= freads file i;
	bd_seek file i1 i2	= fseek file i1 i2;
//	bd_close file files	= fclose file files;
	bd_delta_fp	file	= (0,file);
	bd_freadsubstring i n s f = freadsubstring i n s f
};

import memory;

/*
readByte :: !Int !*Mem -> (!Int,!*Mem);
readWord :: !Int !*Mem -> (!Int,!*Mem);
readHalfWord :: !Int !*Mem -> (!Int,!*Mem);
*/

/*
instance BinaryDynamicIO (!Int,!*Mem)
where {
	bd_readi (ptr,mem)
		# (word,mem)
			= readWord ptr mem
		= (True,word,(ptr + 4,mem));

	bd_reads (ptr,mem) n_characters
		# string
			= createArray n_characters ' ';
		# (ptr,string,mem)
			= bd_reads_loop 0 ptr string mem;
		= (string,(ptr,mem));
	where {
		// kan veel efficienter
		bd_reads_loop i ptr string mem
			| i == n_characters
				= (ptr,string,mem);
			# (c,mem)
				= readByte ptr mem;
			= bd_reads_loop (inc i) (inc ptr) {string & [i] = toChar c} mem;
	};
	
	bd_seek (_,buffer) offset FSeekSet
		= (True,(offset ,buffer));
		
	bd_delta_fp file
		= (0,file);
};
*/
/*
instance BinaryDynamicIO (Int,!*{#Char})
where {
	bd_readi (ptr,buffer)
		# (word,buffer)
			= FromStringToIntU buffer ptr;
		= (True,word,(ptr + 4,buffer));
		
	bd_reads (ptr,buffer) n_characters
		# string
			= createArray n_characters ' ';
		# (ptr,string,buffer)
			= bd_reads_loop 0 ptr string buffer;
		= (string,(ptr,buffer));
	where {
		bd_reads_loop i ptr string buffer
			| i == n_characters
				= (ptr,string,buffer);
			# (c,buffer)
				= buffer![ptr];
			= bd_reads_loop (inc i) (inc ptr) {string & [i] = c} buffer;
	};
			
	bd_seek (_,buffer) offset FSeekSet
		= (True,(offset ,buffer));
		
//	bd_close _ files
//		= (True,files);
		
	bd_delta_fp file
		= (~N_DUMMY_BYTES_BEFORE_DYNAMIC_HEADER,file)
};
*/

//instance Binary

// freadi		:: !*File -> (!Bool,!Int,!*File)
open_dynamic_as_binary :: !String *a -> *(Bool,DynamicHeader,*File,*a) | FileSystem a;
open_dynamic_as_binary file_name files
	#! (ok1,file,files)
		= fopen file_name FReadData files; // fopen
	| not ok1
		= (ok1,default_dynamic_header, stderr, files);
				
	// Build dynamic header
/*
	#! (_,_,file)
		= bd_readi file;
	#! (_,_,file)
		= bd_readi file;
*/
		
	# (ok,dynamic_header,file)
		= read_dynamic_header file;
	= (ok,dynamic_header,file,files);
// where {

N_BYTES_BEFORE_HEADER_START	:== 0;

read_dynamic_header :: !*f -> *(Bool,DynamicHeader,*f) | BinaryDynamicIO f;
read_dynamic_header file
	#! (_,file)
		= bd_seek file N_BYTES_BEFORE_HEADER_START FSeekSet
 	#! (ok3,header_s,file)
		= bd_readi file;
		
//	| True
//		= abort (toString header_s);
		
// NEW ...
	#! header
		= WriteLong (createArray (header_s + 4) ' ') (HEADER_SIZE_OFFSET - 8) header_s;
	#! (_,header,file)
		= bd_freadsubstring (VERSION_NUMBER_OFFSET - 8) header_s header file;
// ... NEW

		
/* OLD; before adding bd_freadsubstring
	#! (header,file)
		= bd_reads file header_s;
*/
	#! (dynamic_header,file)
		= build_dynamic_header header_s header file;

	= (ok3,dynamic_header,file);

// Offset; should correspond with graph_to_string.c
HEADER_SIZE_OFFSET		:== 8;		// header size (in bytes)
VERSION_NUMBER_OFFSET	:== 12;		// version (major,minor) 		// little or big endian format?
GRAPH_OFFSET			:== 16;		// graph offset
GRAPH_SIZE				:== 20;		// graph size
BLOCK_TABLE_OFFSET		:== 24;
BLOCK_TABLE_SIZE		:== 28;
DYNAMIC_RTS_INFO_OFFSET	:== 32;		// info from dynamic rts; filled in by StdDynamic.icl
DYNAMIC_RTS_INFO_SIZE	:== 36;
// End sharing for StdDynamic.icl

STRINGTABLE_OFFSET		:== 40;		// stringtable offset
STRINGTABLE_SIZE		:== 44;		// stringtable size
DESCADDTRESTABLE_OFFSET	:== 48;		// descriptor address table offset
DESCADDRESSTABLE_SIZE	:== 52;		// descriptor address table size
N_NODES					:== 56;

build_dynamic_header :: !Int !String !*f -> (DynamicHeader,!*f) | BinaryDynamicIO f;
build_dynamic_header header_s header file
	#! version_number = FromStringToInt header (VERSION_NUMBER_OFFSET - HEADER_SIZE_OFFSET)
	#! dynamic_header 
		= case (getVersionNumber version_number) of {
			0x00010101
				#! dynamic_header
					= { default_dynamic_header &
						// required
							header_size			= header_s
						,	version_number		= version_number
						,	graph_i				= (FromStringToInt header (GRAPH_OFFSET - HEADER_SIZE_OFFSET)) //+ delta_fp
						,	graph_s				= FromStringToInt header (GRAPH_SIZE - HEADER_SIZE_OFFSET)
						,	block_table_i		= (FromStringToInt header (BLOCK_TABLE_OFFSET - HEADER_SIZE_OFFSET)) //+ delta_fp
						,	block_table_s		= FromStringToInt header (BLOCK_TABLE_SIZE - HEADER_SIZE_OFFSET)
						,	dynamic_rts_info_i	= (FromStringToInt header (DYNAMIC_RTS_INFO_OFFSET - HEADER_SIZE_OFFSET)) //+ delta_fp
						,	dynamic_rts_info_s	= FromStringToInt header (DYNAMIC_RTS_INFO_SIZE - HEADER_SIZE_OFFSET)


						,	stringtable_i		= (FromStringToInt header (STRINGTABLE_OFFSET - HEADER_SIZE_OFFSET)) //+ delta_fp
						,	stringtable_s		= FromStringToInt header (STRINGTABLE_SIZE - HEADER_SIZE_OFFSET)
						,	descriptortable_i	= (FromStringToInt header (DESCADDTRESTABLE_OFFSET - HEADER_SIZE_OFFSET)) //+ delta_fp
						,	descriptortable_s	= FromStringToInt header (DESCADDRESSTABLE_SIZE - HEADER_SIZE_OFFSET)
						,	n_nodes				= FromStringToInt header (N_NODES - HEADER_SIZE_OFFSET)

					};
	//				| True
	//					-> abort (toString (DYNAMIC_RTS_INFO_OFFSET - HEADER_SIZE_OFFSET) +++ " = " +++ toString dynamic_header.dynamic_rts_info_i +++ " - " +++ toString dynamic_header.dynamic_rts_info_s);

			-> dynamic_header;		
			_
				-> abort ("BuildDynamicHeader; unknown version number <" +++ hex_int (getVersionNumber version_number));
		};
	= (dynamic_header,file);
//} // open_dynamic_as_binary

/*
build_dynamic_header :: !Int !String !*f -> (DynamicHeader,!*f) | BinaryDynamicIO f;
build_dynamic_header header_s header file
//	#! (delta_fp,file) = bd_delta_fp file
	#! version_number = FromStringToInt header (12 - 12)
	#! dynamic_header 
		= case (getVersionNumber version_number) of {
			0x00010101
				#! dynamic_header
					= { default_dynamic_header &
						// required
							header_size			= header_s
						,	version_number		= version_number
						,	graph_i				= (FromStringToInt header (GRAPH_OFFSET - 12)) //+ delta_fp
						,	graph_s				= FromStringToInt header (GRAPH_SIZE - 12)
						,	block_table_i		= (FromStringToInt header (BLOCK_TABLE_OFFSET - 12)) //+ delta_fp
						,	block_table_s		= FromStringToInt header (BLOCK_TABLE_SIZE - 12)
						,	dynamic_rts_info_i	= (FromStringToInt header (DYNAMIC_RTS_INFO_OFFSET - 12)) //+ delta_fp
						,	dynamic_rts_info_s	= FromStringToInt header (DYNAMIC_RTS_INFO_SIZE - 12)


						,	stringtable_i		= (FromStringToInt header (STRINGTABLE_OFFSET - 12)) //+ delta_fp
						,	stringtable_s		= FromStringToInt header (STRINGTABLE_SIZE - 12)
						,	descriptortable_i	= (FromStringToInt header (DESCADDTRESTABLE_OFFSET - 12)) //+ delta_fp
						,	descriptortable_s	= FromStringToInt header (DESCADDRESSTABLE_SIZE - 12)
						,	n_nodes				= FromStringToInt header (N_NODES - 12)
							
/*
OLD:
						,	stringtable_i		= FromStringToInt header (24 - 12)
						,	stringtable_s		= FromStringToInt header (28 - 12)
						,	descriptortable_i	= FromStringToInt header (32 - 12)
						,	descriptortable_s	= FromStringToInt header (36 - 12)
						,	n_nodes				= FromStringToInt header (40 - 12)
*/
					};
				-> dynamic_header;		
			_
				-> abort ("BuildDynamicHeader; unknown version number <" +++ hex_int (getVersionNumber version_number));
		};
	= (dynamic_header,file);
//} // open_dynamic_as_binary
*/
close_dynamic_as_binary :: !*File !*f -> (!Bool,!*f) | FileSystem f;
close_dynamic_as_binary file files
	= fclose file files;
	
DYNAMIC_CONTAINS_BLOCKTABLE dynamic_header :== dynamic_header.block_table_i <> 0;
	
// Graph
read_graph_from_dynamic :: DynamicHeader !*f -> (!Bool,!String,!*f) | BinaryDynamicIO f;
read_graph_from_dynamic {graph_i,graph_s} file
	// set file pointer to start of encoded graph
	#! (ok,file)
		= bd_seek file graph_i FSeekSet;
	| not ok
		= (False,{},file);
		
	// read the graph
	#! (graph,file)
		= bd_reads file graph_s;
	= (size graph == graph_s,graph,file);

// BlockTable
:: Block
	= {
		bk_block_n			:: !Int		// block identification
	,	bk_offset			:: !Int		// offset where block starts in encoded graph
	,	bk_size				:: !Int		// block size
	,	bk_n_node_entries	:: !Int		// # block entries - 1
	,	bk_entries			:: {#Int}	// if bk_n_node_entries > 0 then offsets in graph
	};
	
:: BlockTable
	:== {#Block};
	
default_block_table :: BlockTable;
default_block_table = {};
	
default_block :: Block;
default_block
	= {
		bk_block_n			= 0
	,	bk_offset			= 0
	,	bk_size				= 0
	,	bk_n_node_entries	= 0
	,	bk_entries			= {}
	};

read_block_table_from_dynamic :: DynamicHeader !*f -> (!Bool,!BlockTable,!*f) | BinaryDynamicIO f;
read_block_table_from_dynamic dynamic_header=:{block_table_s,block_table_i} file
	| block_table_i == 0
		= abort "read_block_table_from_dynamic: block_table_i <> 0 is not permitted";
		
	// set file pointer to start of block table
	#! (ok,file)
		= bd_seek file block_table_i FSeekSet;
	| not ok
		= (False,{},file);
	
	// read amount of blocks	
	#! (ok,n_blocks,file)
		= bd_readi file;
	| not ok
		= (False,{},file);
		
	#! (delta_fp,file) = bd_delta_fp file
	#! (ok,block_table,file)
		= read_block_table 0 n_blocks delta_fp (createArray n_blocks default_block) file;

	= (ok,block_table,file);
where {
	read_block_table i limit delta_fp block_table file // -> (!Bool,!BlockTable,!*File);
		| i == limit
			= (True,block_table,file);
			
		#! (ok1,bk_block_n,file)
			= bd_readi file;
		#! (ok2,bk_offset,file)
			= bd_readi file;
		#! (ok3,bk_size,file)
			= bd_readi file;
		#! (ok4,bk_n_node_entries,file)
			= bd_readi file;
	
		#! (ok5,bk_entries,file)
			= read_entry_node_offsets 0 bk_n_node_entries (createArray bk_n_node_entries 0) file;
		| ok1 && ok2 && ok3 && ok4 && ok5
			#! block
				= { Block |
					bk_block_n			= /*F ("bk_block_n: " +++ toString bk_block_n)*/ bk_block_n
				,	bk_offset			= bk_offset // fp_offset = graph_i + bk_offset
				,	bk_size				= bk_size
				,	bk_n_node_entries	= bk_n_node_entries
				,	bk_entries			= bk_entries
				};
			= read_block_table (inc i) limit delta_fp {block_table & [bk_block_n] = block} file;
			
			= abort "read_block_table: corrupt dynamic (or internal error)";
	where {
		read_entry_node_offsets :: !Int !Int !*{#Int} !*f -> (!Bool,!*{#Int},!*f) | BinaryDynamicIO f;
		read_entry_node_offsets i limit bk_entries file
			| i == limit			
				= (True,bk_entries,file);
				
				#! file
					= case (i == 0) of {
						True	-> F "  more than one entry node" file;
						False	-> file;
					};
				#! (ok,en_node_offset,file)
					= bd_readi file;
				| not ok
					= (False,bk_entries,file);
				= read_entry_node_offsets (inc i) limit {bk_entries & [i] = en_node_offset} file;
	} // read_block_table
} // read_block_table_from_dynamic
	
/*
read_block_table_from_dynamic :: DynamicHeader !*File -> (!Bool,!BlockTable,!*File);
read_block_table_from_dynamic dynamic_header=:{block_table_s,block_table_i} file
	| block_table_i == 0
		= abort "read_block_table_from_dynamic: block_table_i <> 0 is not permitted";
		
	// set file pointer to start of block table
	#! (ok,file)
		= fseek file block_table_i FSeekSet;
	| not ok
		= (False,{},file);
	
	// read amount of blocks	
	#! (ok,n_blocks,file)
		= freadi file;
	| not ok
		= (False,{},file);
		
	#! (ok,block_table,file)
		= read_block_table 0 n_blocks (createArray n_blocks default_block) file;

	= (ok,block_table,file);
where {
	read_block_table i limit block_table file // -> (!Bool,!BlockTable,!*File);
		| i == limit
			= (True,block_table,file);
			
		#! (ok1,bk_block_n,file)
			= freadi file;
		#! (ok2,bk_offset,file)
			= freadi file;
		#! (ok3,bk_size,file)
			= freadi file;
		#! (ok4,bk_n_node_entries,file)
			= freadi file;
	
		#! (ok5,bk_entries,file)
			= read_entry_node_offsets 0 bk_n_node_entries (createArray bk_n_node_entries 0) file;
		| ok1 && ok2 && ok3 && ok4 && ok5
			#! block
				= { Block |
					bk_block_n			= /*F ("bk_block_n: " +++ toString bk_block_n)*/ bk_block_n
				,	bk_offset			= bk_offset
				,	bk_size				= bk_size
				,	bk_n_node_entries	= bk_n_node_entries
				,	bk_entries			= bk_entries
				};
			= read_block_table (inc i) limit {block_table & [bk_block_n] = block} file;
			
			= abort "read_block_table: corrupt dynamic (or internal error)";
	where {
		read_entry_node_offsets :: !Int !Int !*{#Int} !*File -> (!Bool,!*{#Int},!*File);
		read_entry_node_offsets i limit bk_entries file
			| i == limit			
				= (True,bk_entries,file);
				
				#! file
					= case (i == 0) of {
						True	-> F "  more than one entry node" file;
						False	-> file;
					};
				#! (ok,en_node_offset,file)
					= freadi file;
				| not ok
					= (False,bk_entries,file);
				= read_entry_node_offsets (inc i) limit {bk_entries & [i] = en_node_offset} file;
	} // read_block_table
} // read_block_table_from_dynamic
*/

read_block_table_as_string_from_dynamic :: DynamicHeader !*File -> (!Bool,.{#Char},!*File);
read_block_table_as_string_from_dynamic dynamic_header=:{block_table_s,block_table_i} file
	| block_table_i == 0
		= abort "read_block_table_from_dynamic: block_table_i <> 0 is not permitted";
		
	// set file pointer to start of block table
	#! (ok,file)
		= fseek file block_table_i FSeekSet;
	| not ok
		= (False,{},file);


		
	#! (block_table_as_string,file)
		= freads file block_table_s;
	#! (s_block_table_as_string,block_table_as_string)
		= usize block_table_as_string;
		
	= (s_block_table_as_string == block_table_s,block_table_as_string,file);

// Descriptor Usage Table
:: DescriptorUsageEntry
	= {
		prefix_set_and_string_ptr		:: !Int
	,	dus_library_instance_nr_on_disk	:: !Int
	,	bitset							:: !BitSet
	};
	
:: DescriptorUsageTable
	:== {#.DescriptorUsageEntry};
	
default_descriptor_usage_table :: DescriptorUsageTable;
default_descriptor_usage_table = {};
	
default_descriptor_usage_entry :: !Int -> !.DescriptorUsageEntry;
default_descriptor_usage_entry n_elements
	= { DescriptorUsageEntry |
		prefix_set_and_string_ptr			= 0
	,	dus_library_instance_nr_on_disk		= 0
	,	bitset								= EmptyBitSet //NewBitSet n_elements
	};

////1.3			
//read_descriptor_usage_table_from_dynamic :: DynamicHeader !*File -> (!Bool,!.DescriptorUsageTable,!*File);


read_descriptor_usage_table_from_dynamic :: DynamicHeader !*f -> (!Bool,!.DescriptorUsageTable,!*f) | BinaryDynamicIO f;
read_descriptor_usage_table_from_dynamic dynamic_header=:{descriptortable_i,descriptortable_s} file
//	| False //block_table_i == 0
//		= abort "read_descriptor_usage_table_from_dynamic: internal error the descriptor table does not contain usage sets";

	// set file pointer to start of block table
	#! (ok,file)
		= bd_seek file descriptortable_i FSeekSet;
	| not ok
		= (False,{},file);

	// read size of usage bit set and the amount of usage entries
	#! (ok,usage_bit_set_wsize,n_usage_entries,file)
		= case (DYNAMIC_CONTAINS_BLOCKTABLE dynamic_header) of {
			True
				#! (ok1,usage_bit_set_wsize,file)
					= bd_readi file;
				#! (ok2,n_usage_entries,file)
					= bd_readi file;
				-> (ok1&&ok2,usage_bit_set_wsize,n_usage_entries,file);
			False
				-> (True,0,descriptortable_s >> 2,file);
		};

	| F ("usage_bit_set_wsize: " +++ toString usage_bit_set_wsize) not ok //1 || not ok2
		= (False,{},file);	
		
	// read descriptor usage table
	#! descriptor_usage_table
		= {	(default_descriptor_usage_entry (usage_bit_set_wsize << 5)) \\ i <- [1..n_usage_entries] };
	#! (ok,descriptor_usage_table,file)
		= read_descriptor_usage_table 0 n_usage_entries descriptor_usage_table usage_bit_set_wsize n_usage_entries file;
		
	= (ok,descriptor_usage_table,file);
where {
	read_descriptor_usage_table i limit descriptor_usage_table usage_bit_set_wsize n_usage_entries file
		| i == limit
			= (True,descriptor_usage_table,file);
		
		#! (ok1,prefix_set_and_string_ptr,file)
			= bd_readi file;
		#! (ok2,dus_library_instance_nr_on_disk,file)
			= bd_readi file;
		| dus_library_instance_nr_on_disk == 0
			= abort ("may not be zero, I believe" );
//		| True
//			= abort (toString u);

		#! (ok3,bitset,file)
//			= case (DYNAMIC_CONTAINS_BLOCKTABLE dynamic_header) of {
//				True
			= read_bitset 0 usage_bit_set_wsize (createArray usage_bit_set_wsize 0) file;
//				False
//					-> abort "hallo";
//			};
		| not ok1 || not ok2 || not ok3
			= (False,descriptor_usage_table,file);
			
		// problem with 2.0 compiler
		#! dut 
			= { DescriptorUsageEntry |
				prefix_set_and_string_ptr		= prefix_set_and_string_ptr
			,	dus_library_instance_nr_on_disk	= dus_library_instance_nr_on_disk
			,	bitset							= { BitSet |
													n_elements	= (usage_bit_set_wsize << 5) // upper bound n_usage_entries
												,	map			= bitset
												}
			};
		#! descriptor_usage_table
			= { descriptor_usage_table & [i] = dut};
		= read_descriptor_usage_table (inc i) limit descriptor_usage_table usage_bit_set_wsize n_usage_entries file;
	where {
		read_bitset :: !Int !Int !*{#Int} !*f -> (!Bool,!*{#Int},!*f) | BinaryDynamicIO f;
		read_bitset j limit bitset file
			| j == limit
				= (True,bitset,file);
				
			#! (ok,word_from_bitset,file)
				= bd_readi file;
			| not ok
				= (False,bitset,file);
			
			= read_bitset (inc j) limit { bitset & [j] = word_from_bitset } file;
	} // read_descriptor_usage_table
} // read_descriptor_usage_table_from_dynamic
////3.1

/*
read_descriptor_usage_table_from_dynamic :: DynamicHeader !*File -> (!Bool,!*DescriptorUsageTable,!*File);
read_descriptor_usage_table_from_dynamic {block_table_i,descriptortable_i,descriptortable_s} file
	| block_table_i == 0
		= abort "read_descriptor_usage_table_from_dynamic: internal error the descriptor table does not contain usage sets";

	// set file pointer to start of block table
	#! (ok,file)
		= fseek file descriptortable_i FSeekSet;
	| not ok
		= (False,{},file);

	// read size of usage bit set and the amount of usage entries 
	#! (ok1,usage_bit_set_wsize,file)
		= freadi file;
	#! (ok2,n_usage_entries,file)
		= freadi file;
	| not ok1 || not ok2
		= (False,{},file);	
		
	// read descriptor usage table
	#! descriptor_usage_table
		= {	(default_descriptor_usage_entry (usage_bit_set_wsize << 5)) \\ i <- [1..n_usage_entries] };
	#! (ok,descriptor_usage_table,file)
		= read_descriptor_usage_table 0 n_usage_entries descriptor_usage_table usage_bit_set_wsize file;
		
	= (ok,descriptor_usage_table,file);
where {
	read_descriptor_usage_table i limit descriptor_usage_table usage_bit_set_wsize file
		| i == limit
			= (True,descriptor_usage_table,file);
		
		#! (ok1,prefix_set_and_string_ptr,file)
			= freadi file;
		#! (ok2,descriptor_usage_table,file)
			= read_bitset 0 usage_bit_set_wsize descriptor_usage_table file;
		| not ok1 || not ok2
			= (False,descriptor_usage_table,file);
			
			// problem with 2.0 compiler
			#! descriptor_usage_table
				= { descriptor_usage_table & [i].prefix_set_and_string_ptr = prefix_set_and_string_ptr};
			= read_descriptor_usage_table (inc i) limit descriptor_usage_table usage_bit_set_wsize file;
	where {
		read_bitset j limit descriptor_usage_table file
			| j == limit
				= (True,descriptor_usage_table,file);
				
			#! (ok,word_from_bitset,file)
				= freadi file;
			| not ok
				= (False,descriptor_usage_table,file);
			
			= read_bitset (inc j) limit { descriptor_usage_table & [i].bitset.map.[j] = word_from_bitset } file;
	} // read_descriptor_usage_table
} // read_descriptor_usage_table_from_dynamic
*/


// String Table
:: StringTable
	:== String;
	
read_string_table_from_dynamic :: DynamicHeader !*f -> (!Bool,!StringTable,!*f) | BinaryDynamicIO f;
read_string_table_from_dynamic {stringtable_i,stringtable_s} file
	// set file pointer to start of string table
	#! (ok,file)
		=  bd_seek file stringtable_i FSeekSet;
	| not ok
		= (False,{},file);
		
	#! (string_table,file)
		= bd_reads file stringtable_s;
	= (size string_table == stringtable_s,string_table,file);

// Interface to dynamic run-time system
LinkBlock :: !String !Bool !Int !Int -> (!Int,!Int,!String);
LinkBlock file_name first_time id block_i
	#! msg
		= "Compute2DescAddressTable" +++ file_name +++ 
			"\n" +++ toString first_time +++
			"\n" +++ toString id +++ 
			"\n" +++ toString block_i +++ 
			"\n"
	#! s_adr
		= doreqS msg;


	#! (id,s_adr)
		= case first_time of {
			True
				// diskid_to_runtime_id
				#! (diskid_to_runtimeid,j)
					=  from_string 0 s_adr;
				#! diskid_to_runtimeid
					= to_help_the_type_checker diskid_to_runtimeid;
				| size diskid_to_runtimeid == 0
					-> abort "LinkBlock: internal error";
				// lazy dynamics ...
				#! (di_disk_to_rt_dynamic_indices,j)
					= to_help_the_type_checker3 (from_string j s_adr);
				// ... lazy dynamics

				#! s_adr
					= s_adr % (j,dec (size s_adr));
				#! id			
					= FromStringToInt s_adr 0;
				-> (id,s_adr);
			_
				-> (id,s_adr);
		};
	= (id,FromStringToInt s_adr 4,s_adr % (8,size s_adr));
	// id string_to_graph addresses_of_needed_descriptor_names
where {
	to_help_the_type_checker :: !{#Int} -> !{#Int};
	to_help_the_type_checker i
		= i;
		
	to_help_the_type_checker3 :: (!{#Int},!Int) -> (!{#Int},!Int);
	to_help_the_type_checker3 i = i;
	
};
//	#! s_adr
//		= s_adr % (j,dec (size s_adr));
	//#! s_adr
	//	= (s_adr % (8,size s_adr))

/*
	// id string_to_graph addresses_of_needed_descriptor_names
	= (FromStringToInt s_adr 0,FromStringToInt s_adr 4,s_adr % (8,size s_adr));
*/

	
doreqS :: !String -> !String;
doreqS _ =
	code { 
		ccall DoReqS "S-S"
	};
			
// Utilities
FromStringToInt :: !String !Int -> !Int;
FromStringToInt array i
	= (toInt v0)+(toInt v1<<8)+(toInt v2<<16)+(toInt v3<<24);
where {
	v0= array.[i];
	v1
		= array.[i+1];
	v2 
		= array.[i+2];
	v3  
		= array.[i+3];
} // FromStringToInt

FromStringToIntU :: !*{#Char} !Int -> (!Int,!*{#Char});
FromStringToIntU array i
/*
	#! (s_array,array)
		= usize array;
	| F (toString i +++ " - " +++ toString s_array) i < 0 || ((i + 3) > (dec s_array))
		= abort "error";
*/		
	#! (v0,array)
		= array![i];
	#! (v1,array)
		= array![i+1];
	#! (v2,array)
		= array![i+2];
	#! (v3,array)
		= array![i+3];
	#! i
		= (toInt v0)+(toInt v1<<8)+(toInt v2<<16)+(toInt v3<<24);
	= (i,array);
	
WriteLong :: !*{#Char} !Int !Int -> !*{#Char};
WriteLong array i v
	= { array & [i] 	= (toChar v)		,	[i+1] = (toChar (v>>8)),
				[i+2]	= (toChar (v>>16))  ,	[i+3] = (toChar (v>>24))};

	
hex_int :: !Int -> !String;
hex_int i
	#! b0 
		= hex (i bitand 0x000000ff);
	#! b1
		= hex ((i bitand 0x0000ff00) >> 8);
	#! b2 
		= hex ((i bitand 0x00ff0000) >> 16);
	#! b3
		= hex ((i bitand 0xff000000) >> 24);
	= /*"0x" +++ */ b3 +++ b2 +++ b1 +++ b0;

hexdigit :: !Int -> !Char;
hexdigit i
	| i<10
		= toChar (toInt '0'+i);
		= toChar (toInt 'A'+i-10);

hex :: !Int -> !String;
hex i
	#! i1 
		=(i bitand 0xf0) >> 4;
	#! i2
		=i bitand 0xf;
	= toString (hexdigit i1)+++toString (hexdigit i2);


// 
build_code_lib_name lib_without_extension :== lib_without_extension +++ ".lib";
build_type_lib_name lib_without_extension :== lib_without_extension +++ ".typ";

//
:: LibraryInfo
	= {
		li_code_start	:: !Int
	,	li_code_end		:: !Int
	,	li_data_start	:: !Int
	,	li_data_end		:: !Int
	,	li_name			:: !String		// location where to find the library; access path to library
	,	li_set			:: !Int			// used iff li_name1 == li_name2 and indicates the set of labels to be linked with one instance of library
										// it might be possible to collapse several sets but that is future optimization
	};
	
// in reply from a GraphToString-request; RangeID table
// dependencies: 
// - graph_to_string-conversion routine which uses it to identify the library to which a particular type or
//   piece of code belongs to.
:: RangeID
	= {
		rid_n_range_id_entries	:: !Int
	,	rid_n_type_tables		:: !Int
	,	rid_range_entries		:: !{#RangeIDEntry}
	};
	
:: RangeIDEntry
	= {
		ride_begin_address		:: !Int
	,	ride_end_address		:: !Int
	,	ride_type_table_i		:: !Int
	};
	
default_range_id_entry :: !RangeIDEntry;
default_range_id_entry
	= {
		ride_begin_address		= 0
	,	ride_end_address		= 0
	,	ride_type_table_i		= 0
	};

RID_N_RANGE_ENTRIES_OFFSET		:== 0;
RID_N_TYPE_TABLES_OFFSET		:== 4;
RID_HEADER_SIZE					:== RID_N_TYPE_TABLES_OFFSET + 4;

RIDE_BEGIN_ADDRESS_OFFSET		:== 0;
RIDE_END_ADDRESS_OFFSET			:== 4;
RIDE_RUNTIME_ID_LIB_NUMBER		:== 8;
RIDE_SIZE						:== RIDE_RUNTIME_ID_LIB_NUMBER + 4;

instance toString RangeID
where {
	toString {rid_n_range_id_entries,rid_n_type_tables,rid_range_entries}
		#! range_id
			= createArray (RID_HEADER_SIZE + RIDE_SIZE * rid_n_range_id_entries) '\0';
			
		// Header
		#! range_id
			= WriteLong range_id RID_N_RANGE_ENTRIES_OFFSET rid_n_range_id_entries;
		#! range_id
			= WriteLong range_id RID_N_TYPE_TABLES_OFFSET rid_n_type_tables;
			
		// Entries
		# range_id
			= encode_entry 0 rid_n_range_id_entries RID_HEADER_SIZE range_id
		= range_id; //abort (toString (size range_id));
	where {
		encode_entry i limit offset range_id 
			| i == limit
				= range_id;

				#! {ride_begin_address,ride_end_address,ride_type_table_i}
					= rid_range_entries.[i];
				#! range_id
					= WriteLong range_id (offset +  RIDE_BEGIN_ADDRESS_OFFSET) ride_begin_address;
				#! range_id
					= WriteLong range_id (offset +  RIDE_END_ADDRESS_OFFSET) ride_end_address;
				#! range_id
					= WriteLong range_id (offset +  RIDE_RUNTIME_ID_LIB_NUMBER) ride_type_table_i; //(ride_type_table_i << 12);
				= encode_entry (inc i) limit (offset + RIDE_SIZE) range_id;
	};
};

// Type table usage table; constructed in dynamic_to_string
TTUT_UNUSED	:== 0xffffffff;

// dynamic info
:: DynamicInfo
	= {
		// Header
		di_version					:: !Version
	,	di_string_table				:: !StringTable
	,	di_descriptor_usage_table	:: !DescriptorUsageTable
	,	di_file_name				:: !String
	,	di_n_blocks					:: !Int

	

	// read_rts_info_from_dynamic reads the following fields
	// begin
	,	di_library_instance_to_library_index	:: !{#LibraryInstanceToLibraryIndexInfo}		// indexed by a RunTimeID, index in di_library_index_to_library_name
	,	di_library_index_to_library_name		:: !{#{#Char}}	// indexed by index from above array, string reference to {code,type}-library
//	,	di_external_dynamics					:: !{#{#Char}}  // references to (other) dynamics
	,	di_disk_type_equivalent_classes			:: !{DiskTypeEquivalentClass}
	,	di_lazy_dynamics_a						:: !{#{#Char}}
	,	di_lazy_type_reference_a				:: !{Maybe LazyTypeReference}
	
	// DiskTypeEquivalentClass
	// end
	
	//
	,	di_disk_id_to_library_instance_i		:: !{#Int}		// indexed by diskID
	,	di_disk_to_rt_dynamic_indices			:: !{#Int}		// ibdexed by disk_dynamic_index

	,	di_has_block_been_used					:: !{#Bool}		// indexed by block index from BlockTable
	};	

:: LibraryInstanceToLibraryIndexInfo
	= {
		litlii_index_in_di_library_index_to_library_name	:: !Int
	,	litlii_used_by_code									:: !Bool
	,	litlii_used_by_type									:: !Bool
	};
	
instance DefaultElem LibraryInstanceToLibraryIndexInfo
where {
	default_elem
		= { 
			litlii_index_in_di_library_index_to_library_name	= 0
		,	litlii_used_by_code									= False
		,	litlii_used_by_type									= False
		};
};
	
read_rts_info_from_dynamic :: DynamicHeader !*f -> (!Bool,!DynamicInfo,!*f) | BinaryDynamicIO f;
read_rts_info_from_dynamic {dynamic_rts_info_i,dynamic_rts_info_s} file
	# r = (toString dynamic_rts_info_i +++ " - " +++ toString dynamic_rts_info_s)
	| F r True
//		= abort ;
	// set file pointer to start of string table
	#! (ok,file)
		=  bd_seek file dynamic_rts_info_i FSeekSet;
	| not ok
		= (False,default_elem,file);
		
		
	#! (dynamic_rts_info,file)
		= bd_reads file dynamic_rts_info_s;
		
	| size dynamic_rts_info <> dynamic_rts_info_s
		= (False,default_elem,file);
	
//		= abort "llla" <<- (f (decode dynamic_rts_info)); //
		= (True,decode dynamic_rts_info,file);
		
//import RWSDebug;
f :: !DynamicInfo -> !DynamicInfo;
f t = t;
	
class DynamicInfoOps s
where {
	UpdateDynamicInfo :: !Int !DynamicInfo !*s -> !*s
};

//1.3
instance DynamicInfoOps (!*{#DynamicInfo})
//3.1
/*2.0
instance DynamicInfoOps ({#DynamicInfo})
0.2*/
where {
	UpdateDynamicInfo dynamic_info_index dynamic_info a
		# (n_dynamic_infos,a)
			= usize a;
		| dynamic_info_index < n_dynamic_infos
			= { a & [dynamic_info_index] = dynamic_info };
			
		# new_dynamic_infos
			= createArray (inc dynamic_info_index) default_dynamic_info;
		# new_dynamic_infos
			= { new_dynamic_infos & [dynamic_info_i] = a.[dynamic_info_i] \\ dynamic_info_i <- [0..dec n_dynamic_infos] }
		# new_dynamic_infos
			= { new_dynamic_infos & [dynamic_info_index] = dynamic_info };
		= new_dynamic_infos;
};

/*2.0


0.2*/


	
// non-unique, straight-forward conversions
class EnDecode a 
where {
	to_size	:: a -> !Int;
	to_string :: a !Int !*{#Char} -> (!Int,!*{#Char});
	from_string :: !Int !{#Char} -> (a,!Int);
	
	encode :: a -> !*{#Char} | EnDecode a;
	encode a :== snd (to_string a 0 (createArray (to_size a) '@'));

	decode :: !{#Char} -> a | EnDecode a;
	decode buffer :== fst (from_string 0 buffer)
		
};


ENDECODE_INT_SIZE	:== 4;
instance EnDecode Int
where {
	to_size _				  	= ENDECODE_INT_SIZE;
	to_string i offset buffer 	= (offset + ENDECODE_INT_SIZE, WriteLong buffer offset i);
	
	from_string offset buffer	
		# i
			= FromStringToInt buffer offset;
		= (i,offset + ENDECODE_INT_SIZE);
};

ENDECODE_CHAR_SIZE	:== 1;
instance EnDecode Char
where {
	to_size _				  = ENDECODE_CHAR_SIZE;
	to_string i offset buffer = (offset + ENDECODE_CHAR_SIZE,  { buffer & [offset] = i });

	from_string offset buffer
		# c
			= buffer.[offset];
		= (c,offset + ENDECODE_CHAR_SIZE);
};

ENDECODE_BOOL_SIZE	:== 1;
ENDECODE_BOOL_TRUE	:== 0;
ENDECODE_BOOL_FALSE	:== 1;
instance EnDecode Bool
where {
	to_size _				  = ENDECODE_BOOL_SIZE;
	to_string b offset buffer = (offset + ENDECODE_BOOL_SIZE,  { buffer & [offset] = toChar (if b ENDECODE_BOOL_TRUE ENDECODE_BOOL_FALSE) });

	from_string offset buffer
		# c
			= buffer.[offset];
		= (if ((toInt c) == ENDECODE_BOOL_TRUE) True False,offset + ENDECODE_BOOL_SIZE);
};

/*
/*2.0
instance EnDecode {a} | EnDecode, DefaultElem a & Array {} a
0.2*/
where {
	to_size _	= abort "aa";
	to_string i offset buffer = abort "aa";

	from_string offset buffer = abort "aa";

};
*/

/*
instance EnDecode {!a} | EnDecode, select_u, size_u, createArray_u, DefaultElem, ArrayElem a
where { 
	to_size array
		= abort "a";
		
	to_string array offset buffer
		= abort "a";	
	from_string offset buffer
		= abort "aa";
};
*/

ENDECODE_ARRAY_SIZE	:== 4;
//1.3
instance EnDecode {#b} | EnDecode b & DefaultElem b & ArrayElem b
//3.1
/*2.0
instance EnDecode {#a} | EnDecode, DefaultElem a & Array {#} a
0.2*/
where {
	to_size array
		= ENDECODE_ARRAY_SIZE + (to_size_array 0 (size array) 0);
	where {
		to_size_array :: !Int !Int !Int -> !Int;
		to_size_array i limit total_size
			| i == limit
				= total_size;
			= to_size_array (inc i) limit (total_size + (to_size array.[i]));
	};
	
	to_string array offset buffer
		# buffer
			= WriteLong buffer offset s_array;
		= to_string_array 0 s_array (offset + ENDECODE_ARRAY_SIZE) buffer;
	where {
		to_string_array i limit offset buffer
			| i == limit
				= (offset,buffer);
			# (offset,buffer)
				= to_string array.[i] offset buffer;
			= to_string_array (inc i) limit offset buffer;
	
		s_array
			= size array
	};

	from_string offset buffer
		# s_array
			= FromStringToInt buffer offset;
		# a
			= createArray s_array default_elem;
//		| F ("*** " +++ toString s_array) True
		= from_string_array 0 s_array a (offset + ENDECODE_ARRAY_SIZE) buffer;
	where {
		from_string_array i limit array offset buffer
			| i == limit
				= (array,offset);

			# (elem,offset)
				= from_string offset buffer;
			= from_string_array (inc i) limit {array & [i] = elem} offset buffer;
	}
};

// ---------
// copy of above but without #.
//1.3
instance EnDecode {b} | EnDecode b & DefaultElem b & ArrayElem b
//3.1
/*2.0
instance EnDecode {a} | EnDecode, DefaultElem a & Array {} a
0.2*/
where {
	to_size array
		= ENDECODE_ARRAY_SIZE + (to_size_array 0 (size array) 0);
	where {
		to_size_array :: !Int !Int !Int -> !Int;
		to_size_array i limit total_size
			| i == limit
				= total_size;
			= to_size_array (inc i) limit (total_size + (to_size array.[i]));
	};
	
	to_string array offset buffer
		# buffer
			= WriteLong buffer offset s_array;
		= to_string_array 0 s_array (offset + ENDECODE_ARRAY_SIZE) buffer;
	where {
		to_string_array i limit offset buffer
			| i == limit
				= (offset,buffer);
			# (offset,buffer)
				= to_string array.[i] offset buffer;
			= to_string_array (inc i) limit offset buffer;
	
		s_array
			= size array
	};

	from_string offset buffer
		# s_array
			= FromStringToInt buffer offset;
		# a
			= createArray s_array default_elem;
//		| F ("*** " +++ toString s_array) True
		= from_string_array 0 s_array a (offset + ENDECODE_ARRAY_SIZE) buffer;
	where {
		from_string_array i limit array offset buffer
			| i == limit
				= (array,offset);

			# (elem,offset)
				= from_string offset buffer;
			= from_string_array (inc i) limit {array & [i] = elem} offset buffer;
	}
};

instance EnDecode DynamicInfo
where {
	to_size {di_library_instance_to_library_index,di_library_index_to_library_name,di_disk_type_equivalent_classes,di_lazy_dynamics_a,di_lazy_type_reference_a}
		= to_size di_library_instance_to_library_index + to_size  di_library_index_to_library_name + to_size di_disk_type_equivalent_classes + to_size di_lazy_dynamics_a + to_size di_lazy_type_reference_a;

	to_string {di_library_instance_to_library_index,di_library_index_to_library_name,di_disk_type_equivalent_classes,di_lazy_dynamics_a,di_lazy_type_reference_a} offset buffer
		# (offset,buffer)
			= to_string di_library_instance_to_library_index offset buffer;
		# (offset,buffer)
			= to_string di_library_index_to_library_name offset buffer;
		# (offset,buffer)
			= to_string di_disk_type_equivalent_classes offset buffer;
		# (offset,buffer)
			= to_string di_lazy_dynamics_a offset buffer;
		# (offset,buffer)
			= to_string di_lazy_type_reference_a offset buffer;
		= (offset,buffer);

	from_string offset buffer
		#! (di_library_instance_to_library_index,offset)
			= from_string offset buffer;
		#! (di_library_index_to_library_name,offset)
			= from_string offset buffer;
		#! (di_disk_type_equivalent_classes,offset)
			= from_string offset buffer;
		#! (di_lazy_dynamics_a,offset)
			= from_string offset buffer;
		#! (di_lazy_type_reference_a,offset)
			= from_string offset buffer;
			
		#! di
			= { default_elem &
				di_library_instance_to_library_index	= di_library_instance_to_library_index
			,	di_library_index_to_library_name		= di_library_index_to_library_name
			,	di_disk_type_equivalent_classes			= di_disk_type_equivalent_classes
			,	di_lazy_dynamics_a						= di_lazy_dynamics_a
			,	di_lazy_type_reference_a				= di_lazy_type_reference_a
			};
		= (di,offset);	
};

instance DefaultElem DynamicInfo
where {
	default_elem
		= default_dynamic_info;
};
		
default_dynamic_info :: !DynamicInfo;
default_dynamic_info 
	= {
		di_version								= DefaultVersion
	,	di_string_table							= {}
	,	di_descriptor_usage_table				= default_descriptor_usage_table
	,	di_file_name							= {}
	,	di_n_blocks								= 0

	
	// part being stored in a dynamic
	,	di_library_instance_to_library_index	= {}
	,	di_library_index_to_library_name		= {}
//	,	di_external_dynamics					= {}
	,	di_disk_type_equivalent_classes			= {}
	,	di_lazy_dynamics_a						= {}
	,	di_lazy_type_reference_a				= {}
	
	//
	,	di_disk_id_to_library_instance_i		= {}		// indexed by diskID
	,	di_disk_to_rt_dynamic_indices			= {}
	
	,	di_has_block_been_used					= {}

	};
	
	
/*
instance toString DynamicInfo
where {
	toString {di_version,di_library_table,di_string_table}
		#! encoded_dynamic_info
			= createArray (4 + (4 + s_di_library_table) + (4 + s_di_string_table)) '0';
			
		// Header
		#! encoded_dynamic_info
			= WriteLong encoded_dynamic_info 0 di_version;
			
		// Library table
		#! encoded_dynamic_info
			= WriteLong encoded_dynamic_info DI_VERSION_OFFSET di_version;
		

		= encoded_dynamic_info;
	where { 
		s_di_library_table
			= size di_library_table;
		s_di_string_table
			= size di_string_table;
	};
};
*/

// communication between application and client
:: TypeReference
	= {
		tr_type_name	:: !String
	,	tr_module_name1	:: !String
	,	tr_module_name2	:: !String
	,	tr_library1		:: !LibraryID
	,	tr_library2		:: !LibraryID
	};
	
instance DefaultElem TypeReference
where {
	default_elem 
		 = {
			tr_type_name	= {}
		,	tr_module_name1	= {}
		,	tr_module_name2	= {}
		,	tr_library1		= default_elem
		,	tr_library2		= default_elem
		};
};

:: LibraryID
	= Address !Int
	| Number !Int
	;
	
instance DefaultElem LibraryID
where {
	default_elem 
		= Address 0
};


ENDECODE_LIBRARYID_SIZE	:== 1;
ENDECODE_ADDRESS 	:== 0;
ENDECODE_NUMBER		:== 1;

instance EnDecode LibraryID
where {
	to_size (Address i)
		= ENDECODE_LIBRARYID_SIZE + to_size i;
	to_size (Number i)
		= ENDECODE_LIBRARYID_SIZE + to_size i;
	
	to_string x=:(Address i) offset buffer 	
		# buffer
			= { buffer & [offset] = toChar ENDECODE_ADDRESS };
	    = (offset + to_size x, WriteLong buffer (offset + ENDECODE_LIBRARYID_SIZE) i);
	    
	to_string x=:(Number i) offset buffer 	
		# buffer
			= { buffer & [offset] = toChar ENDECODE_NUMBER };
	    = (offset + to_size x, WriteLong buffer (offset + ENDECODE_LIBRARYID_SIZE) i);
	
	from_string offset buffer	
		# library_id
			= buffer.[offset];
		# i
			= FromStringToInt buffer (offset + ENDECODE_LIBRARYID_SIZE);
		# library_id
			= toInt library_id;
		| library_id == ENDECODE_ADDRESS
			#! x = Address i
			= (x, offset + to_size x);
		| library_id == ENDECODE_NUMBER
			#! x = Number i
			= (x, offset + to_size x);
};

instance EnDecode TypeReference
where {
	to_size {tr_type_name,tr_module_name1,tr_module_name2,tr_library1,tr_library2}
		= to_size tr_type_name + to_size tr_module_name1 + to_size tr_module_name2 + to_size tr_library1 + to_size tr_library2;
		
	to_string {tr_type_name,tr_module_name1,tr_module_name2,tr_library1,tr_library2} offset buffer
		# (offset,buffer)
			= to_string tr_type_name offset buffer;
		# (offset,buffer)
			= to_string tr_module_name1 offset buffer;
		# (offset,buffer)
			= to_string tr_module_name2 offset buffer;
		# (offset,buffer)
			= to_string tr_library1 offset buffer;
		# (offset,buffer)
			= to_string tr_library2 offset buffer;
		= (offset,buffer);
			
	from_string offset buffer
		# (tr_type_name,offset)
			= from_string offset buffer;
		# (tr_module_name1,offset)
			= from_string offset buffer;
		# (tr_module_name2,offset)
			= from_string offset buffer;
		# (tr_library1,offset)
			= from_string offset buffer;
		# (tr_library2,offset)
			= from_string offset buffer;
			
		# type_ref
			= { 
				tr_type_name 	= tr_type_name
			,	tr_module_name1	= tr_module_name1
			,	tr_module_name2	= tr_module_name2
			,	tr_library1		= tr_library1
			,	tr_library2		= tr_library2
			};
		= (type_ref,offset);
		

};

ENDECODE_LIST_SIZE	:== 4;
/*2.0
instance EnDecode [b] | EnDecode, DefaultElem b &  Array {#} b
0.2*/
//1.3
instance EnDecode [b] | EnDecode b //& DefaultElem b & ArrayElem b
//3.1
where {
	to_size list
		= ENDECODE_LIST_SIZE + (to_size_list list 0);
	where {
		to_size_list [x:xs] total_size
			= to_size_list xs (to_size x + total_size);
		to_size_list [] total_size
			= total_size;
	};
	
	to_string list offset buffer
//		= to_string (resolve_overloading2 {e \\ e <- list}) offset buffer;
		# (last_offset,buffer,n_elements)
			= to_string2 list (ENDECODE_LIST_SIZE + offset) buffer 0;
		# buffer
			= WriteLong buffer offset n_elements;
		= (last_offset,buffer);
	where {
		to_string2 [x:xs] offset buffer i
			# (offset,buffer)
				= to_string x offset buffer;
			= to_string2 xs offset buffer (inc i);
		to_string2 [] offset buffer i
			= (offset,buffer,i);
	};

	from_string offset buffer
		# s_list
			= FromStringToInt buffer offset;
		= from_string2 0 s_list [] buffer (ENDECODE_LIST_SIZE + offset);
//		= abort ("^^^^ " +++ toString s_list);
	where {
		from_string2 i limit accu buffer offset
			| i == limit
				= (reverse accu,offset);
			# (x,offset)
				= from_string offset buffer;
			= from_string2 (inc i) limit [x:accu] buffer offset;
	};
				

/*
		# (array,offset,buffer)
			= from_string offset buffer;
		= ([ a \\ a <-: resolve_overloading2 array ],offset,buffer);
*/		
/*
	from_string offset buffer
		# (s_array,buffer)
			= FromStringToIntU buffer offset;
		# a
			= createArray s_array default_elem;
		| F ("*** " +++ toString s_array) True
		= from_string_array 0 s_array a (offset + ENDECODE_ARRAY_SIZE) buffer;
	where {
		from_string_array i limit array offset buffer
			| i == limit
				= (array,offset,buffer);

			# (elem,offset,buffer)
				= from_string offset buffer;
			= from_string_array (inc i) limit {array & [i] = elem} offset buffer;
*/
};

/*2.0
resolve_overloading2 :: {#a} -> {#a} | EnDecode, DefaultElem a & Array {#} a;
0.2*/
//1.3
resolve_overloading2 :: {#a} -> {#a} | EnDecode a & DefaultElem a & ArrayElem a;
//3.1
resolve_overloading2 i = i;

// RunTimeID/DiskID  at run-time:
RTID_DATA_DYNAMIC				:== 0; // no code needed

// RunTimeID at run-time
RTID_LIBRARY_INSTANCE_ID_START	:== 1; // by default, a dummy element is created

// Otherwise
RTID_DISKID_RENUMBER_START		:== 1; // change also gts_range_id

// Build (lazy) block labels
BUILD_BLOCK_LABEL				:== "e____SystemDynamic__nbuild__block";
BUILD_LAZY_BLOCK_LABEL			:== "e____SystemDynamic__nbuild__lazy__block";

// BUILD_BLOCK (run-time) format, from gts_build_block.c, _SystemDynamic.{dcl,icl}
BUILD_DYNAMIC_NODE__INDEX_PTR	:== 4;
BUILD_DYNAMIC_GDID__PTR			:== 8;


// BUILD_BLOCK (on disk) format, from gts_build_block.c:
BUILD_LAZY_DYNAMIC_ON_DISK__NODE_INDEX		:== 0;
BUILD_LAZY_DYNAMIC_ON_DISK__DYNAMIC_ID		:== 4;

BUILD_LAZY_DYNAMIC_ON_DISK__LAST_FIELD		:== (BUILD_LAZY_DYNAMIC_ON_DISK__DYNAMIC_ID + 4);
BUILD_LAZY_DYNAMIC_ON_DISK__BSIZE			:== BUILD_LAZY_DYNAMIC_ON_DISK__LAST_FIELD;

// A lazy dynamic reference is generated by the graph_to_string conversion routine. Update also
// gts_lazy_dynamic_reference.c
:: LazyDynamicReference
	= { 
		ldr_id							:: !Int			// run-time id of lazy dynamic
	,	ldr_site						:: !String		// e.g. path to dynamic
	,	ldr_lazy_dynamic_index			:: !Int			// disk id for lazy dynamic (block)
	};
	
// all instance of the graph_to_string-conversion function *must* use the same LazyDynamicReference.
LazyDynamicReference_String		:== "LazyDynamicReference";

StdDynamicLowLevelInterfaceModule_String	:== "StdDynamicLowLevelInterface";

GlobalDynamicInfoDummy_String 	:== "GlobalDynamicInfoDummy";

instance DefaultElem LazyDynamicReference
where {
	default_elem 
		= { 
			ldr_id					= default_elem
		,	ldr_site				= default_elem
		,	ldr_lazy_dynamic_index	= default_elem
		};
};

instance EnDecode LazyDynamicReference
where {
	to_size {ldr_id,ldr_site,ldr_lazy_dynamic_index}
		= to_size ldr_id + to_size ldr_site + to_size ldr_lazy_dynamic_index;
		
	to_string {ldr_id,ldr_site,ldr_lazy_dynamic_index} offset buffer
		# (offset,buffer)
			= to_string ldr_id offset buffer;
		# (offset,buffer)
			= to_string ldr_site offset buffer;
		# (offset,buffer)
			= to_string ldr_lazy_dynamic_index offset buffer;
		= (offset,buffer);
			
	from_string offset buffer
		# (ldr_id,offset)
			= from_string offset buffer;
		# (ldr_site,offset)
			= from_string offset buffer;
		# (ldr_lazy_dynamic_index,offset)
			= from_string offset buffer;
			
		# lazy_dynamic_reference
			= { 
				ldr_id 					= ldr_id
			,	ldr_site				= ldr_site
			,	ldr_lazy_dynamic_index	= ldr_lazy_dynamic_index
			};
		= (lazy_dynamic_reference,offset);
};

// Representation on disk	
:: DiskTypeEquivalentClass
	= {
	// encoded:
		dtec_type_equations			:: !{DiskTypeReference}
	,	dtec_lazy_type_equations	:: !{DiskTypeReference}
	
	//
	,	dtec_type_implementation_table_index	:: !Maybe !Int
	};



instance EnDecode DiskTypeEquivalentClass
where {
	to_size {dtec_type_equations,dtec_lazy_type_equations}
		= to_size dtec_type_equations + to_size dtec_lazy_type_equations;
		
	to_string {dtec_type_equations,dtec_lazy_type_equations} offset buffer
		# (offset,buffer)
			= to_string dtec_type_equations offset buffer;
		# (offset,buffer)
			= to_string dtec_lazy_type_equations offset buffer;
		= (offset,buffer);
			
	from_string offset buffer
		# (dtec_type_equations,offset)
			= from_string offset buffer;
		# (dtec_lazy_type_equations,offset)
			= from_string offset buffer;
			
		# disk_type_equivalent_class
			= { 
				dtec_type_equations 		= dtec_type_equations
			,	dtec_lazy_type_equations	= dtec_lazy_type_equations
			
			,	dtec_type_implementation_table_index	= Nothing
			};
		= (disk_type_equivalent_class,offset);
};

instance DefaultElem DiskTypeEquivalentClass
where {
	default_elem
		= { 
			dtec_type_equations			= {}
		,	dtec_lazy_type_equations	= {}
		
		,	dtec_type_implementation_table_index	= Nothing
		};
};
		
:: DiskTypeReference
	= 
	 DiskTypeRef DiskTypeRef						// dtr_library_instance_i applies to the di_disk_id_to_library_instance_i of the current dynamic
	| LazyDiskTypeRef LazyDiskTypeRef				// dtr_library_instance_i applies to the di_disk_id_to_library_instance_i of lazy dynamic ldtr_lazy_dynamic_index
	;
	
ENDECODE_DISKTYPEREFERENCEID_SIZE	:== 1;
ENDECODE_DISKTYPEREF			 	:== 0;
ENDECODE_LAZYDISKTYPEREF			:== 1;

instance EnDecode DiskTypeReference
where {
	to_size (DiskTypeRef i)
		= ENDECODE_DISKTYPEREFERENCEID_SIZE + to_size i;
	to_size (LazyDiskTypeRef i)
		= ENDECODE_DISKTYPEREFERENCEID_SIZE + to_size i;
	
	to_string x=:(DiskTypeRef i) offset buffer 	
		# buffer
			= { buffer & [offset] = toChar ENDECODE_DISKTYPEREF };
		# (offset,buffer)
			= to_string i (offset + ENDECODE_DISKTYPEREFERENCEID_SIZE) buffer;
		= (offset,buffer);		
//	    = (offset + to_size x, WriteLong buffer (offset + ENDECODE_DISKTYPEREFERENCEID_SIZE) i);
	    
	to_string x=:(LazyDiskTypeRef i) offset buffer 	
		# buffer
			= { buffer & [offset] = toChar ENDECODE_LAZYDISKTYPEREF };
		# (offset,buffer)
			= to_string i (offset + ENDECODE_DISKTYPEREFERENCEID_SIZE) buffer;
		= (offset,buffer);
//	    = (offset + to_size x, WriteLong buffer (offset + ENDECODE_DISKTYPEREFERENCEID_SIZE) i);
	
	from_string offset buffer	
		# disk_type_reference_id
			= toInt (buffer.[offset]);
		| disk_type_reference_id == ENDECODE_DISKTYPEREF
			#! (disk_type_ref,offset)
				= from_string (offset + ENDECODE_DISKTYPEREFERENCEID_SIZE) buffer;
			#! x = DiskTypeRef disk_type_ref
			= (x, offset /*+ to_size x*/);
		| disk_type_reference_id == ENDECODE_LAZYDISKTYPEREF
			#! (lazy_disk_type_ref,offset)
				= from_string (offset + ENDECODE_DISKTYPEREFERENCEID_SIZE) buffer;
			#! x = LazyDiskTypeRef lazy_disk_type_ref
			= (x, offset /*+ to_size x*/);
};

instance DefaultElem DiskTypeReference
where {
	default_elem
		= DiskTypeRef default_elem;
};
	
:: LazyDiskTypeRef
	= { 
	// LazyDynamicReference, the path can be found for the external dynamics. The conversion-routine need not deliver the
	// string itself.
		ldtr_lazy_dynamic_index	:: !Int				// index of lazy_dynamic_a of DynamicInfo-record (build_lazy_block)
	,	ldtr_disk_type_ref		:: !DiskTypeRef
	};

instance EnDecode LazyDiskTypeRef
where {
	to_size {ldtr_lazy_dynamic_index,ldtr_disk_type_ref}
		= to_size ldtr_lazy_dynamic_index + to_size ldtr_disk_type_ref;
		
	to_string {ldtr_lazy_dynamic_index,ldtr_disk_type_ref} offset buffer
		# (offset,buffer)
			= to_string ldtr_lazy_dynamic_index offset buffer;
		# (offset,buffer)
			= to_string ldtr_disk_type_ref offset buffer;
		= (offset,buffer);
			
	from_string offset buffer
		# (ldtr_lazy_dynamic_index,offset)
			= from_string offset buffer;
		# (ldtr_disk_type_ref,offset)
			= from_string offset buffer;
			
		# lazy_disk_type_ref
			= { 
				ldtr_lazy_dynamic_index 	= ldtr_lazy_dynamic_index
			,	ldtr_disk_type_ref			= ldtr_disk_type_ref
			};
		= (lazy_disk_type_ref,offset);
};

instance DefaultElem LazyDiskTypeRef
where {
	default_elem
		= { 
			ldtr_lazy_dynamic_index 	= default_elem
		,	ldtr_disk_type_ref			= default_elem
		}
};
		
:: DiskTypeRef
	= { 
		dtr_library_instance_i	:: !Int				// index in di_disk_id_to_library_instance_i either from current dynamic or from lazy dynamic (depends on the context)
	,	dtr_tr_module_n			:: !Int
	,	dtr_tr_type_def_n		:: !Int
	};

instance EnDecode DiskTypeRef
where {
	to_size {dtr_library_instance_i,dtr_tr_module_n,dtr_tr_type_def_n}
		= to_size dtr_library_instance_i + to_size dtr_tr_module_n + to_size dtr_tr_type_def_n;
		
	to_string {dtr_library_instance_i,dtr_tr_module_n,dtr_tr_type_def_n} offset buffer
		# (offset,buffer)
			= to_string dtr_library_instance_i offset buffer;
		# (offset,buffer)
			= to_string dtr_tr_module_n offset buffer;
		# (offset,buffer)
			= to_string dtr_tr_type_def_n offset buffer;
		= (offset,buffer);
			
	from_string offset buffer
		# (dtr_library_instance_i,offset)
			= from_string offset buffer;
		# (dtr_tr_module_n,offset)
			= from_string offset buffer;
		# (dtr_tr_type_def_n,offset)
			= from_string offset buffer;

			
		# disk_type_ref
			= { 
				dtr_library_instance_i 	= dtr_library_instance_i
			,	dtr_tr_module_n			= dtr_tr_module_n
			,	dtr_tr_type_def_n		= dtr_tr_type_def_n
			};
		= (disk_type_ref,offset);
};

instance DefaultElem DiskTypeRef
where {
	default_elem
		= {
			dtr_library_instance_i	= 0
		,	dtr_tr_module_n			= 0
		,	dtr_tr_type_def_n		= 0
		};
};

INITIAL_LAZY_DYNAMIC_INDEX	:== 100;

/*2.0
instance EnDecode (a,b) | EnDecode a & EnDecode b;
0.2*/
//1.3
instance EnDecode (a,b) | EnDecode b & EnDecode a
//3.1
where {
	to_size (a,b)
		= to_size a + to_size b;
	
	to_string (a,b) offset buffer
		# (offset,buffer)
			= to_string a offset buffer;
		# (offset,buffer)
			= to_string b offset buffer;
		= (offset,buffer);

	from_string offset buffer
		# (a,offset)
			= from_string offset buffer;
		# (b,offset)
			= from_string offset buffer;
		= ((a,b),offset);

};

/*2.0
instance EnDecode (a,b,c,d) | EnDecode a & EnDecode b & EnDecode c & EnDecode d;
0.2*/
//1.3
instance EnDecode (a,b,c,d) | EnDecode a & EnDecode b & EnDecode c & EnDecode d
//3.1
where {
	to_size (a,b,c,d)
		= to_size a + to_size b + to_size c + to_size d;
	
	to_string (a,b,c,d) offset buffer
		# (offset,buffer)
			= to_string a offset buffer;
		# (offset,buffer)
			= to_string b offset buffer;
		# (offset,buffer)
			= to_string c offset buffer;
		# (offset,buffer)
			= to_string d offset buffer;
		= (offset,buffer);

	from_string offset buffer
		# (a,offset)
			= from_string offset buffer;
		# (b,offset)
			= from_string offset buffer;
		# (c,offset)
			= from_string offset buffer;
		# (d,offset)
			= from_string offset buffer;

		= ((a,b,c,d),offset);

};

/*2.0
instance EnDecode (a,b,c,d,e) | EnDecode a & EnDecode b & EnDecode c & EnDecode d & EnDecode e
0.2*/
//1.3
instance EnDecode (a,b,c,d,e) | EnDecode a & EnDecode b & EnDecode c & EnDecode d & EnDecode e
//3.1
where {
	to_size (a,b,c,d,e)
		= to_size a + to_size b + to_size c + to_size d + to_size e;
	
	to_string (a,b,c,d,e) offset buffer
		# (offset,buffer)
			= to_string a offset buffer;
		# (offset,buffer)
			= to_string b offset buffer;
		# (offset,buffer)
			= to_string c offset buffer;
		# (offset,buffer)
			= to_string d offset buffer;
		# (offset,buffer)
			= to_string e offset buffer;

		= (offset,buffer);

	from_string offset buffer
		# (a,offset)
			= from_string offset buffer;
		# (b,offset)
			= from_string offset buffer;
		# (c,offset)
			= from_string offset buffer;
		# (d,offset)
			= from_string offset buffer;
		# (e,offset)
			= from_string offset buffer;

		= ((a,b,c,d,e),offset);

};

// interface to graph_to_string-routine
// update gts_code_and_type_runtime_ids.c
CODE_LIBRARY_INSTANCE	:== 0x80000000;
TYPE_LIBRARY_INSTANCE	:== 0x40000000;
LIBRARY_INSTANCE_MASK	:== 0x3fffffff;

GET_LIBRARY_INSTANCE_I x	:== x bitand LIBRARY_INSTANCE_MASK;

IS_CODE_LIBRARY_INSTANCE x 	:== (x bitand CODE_LIBRARY_INSTANCE) <> 0;
IS_TYPE_LIBRARY_INSTANCE x	:== (x bitand TYPE_LIBRARY_INSTANCE) <> 0;

/*
:: LibraryInstanceToLibraryIndexInfo
	= {
		litlii_index_in_di_library_index_to_library_name	:: !Int
	,	litlii_used_by_code									:: !Bool
	,	litlii_used_by_type									:: !Bool
	};
*/

instance EnDecode LibraryInstanceToLibraryIndexInfo
where {
	to_size {litlii_index_in_di_library_index_to_library_name,litlii_used_by_code,litlii_used_by_type}
		= to_size litlii_index_in_di_library_index_to_library_name + to_size litlii_used_by_code + to_size litlii_used_by_type;

	to_string {litlii_index_in_di_library_index_to_library_name,litlii_used_by_code,litlii_used_by_type} offset buffer
		# (offset,buffer)
			= to_string litlii_index_in_di_library_index_to_library_name offset buffer;
		# (offset,buffer)
			= to_string litlii_used_by_code offset buffer;
		# (offset,buffer)
			= to_string litlii_used_by_type offset buffer;
		= (offset,buffer);

	from_string offset buffer
		#! (litlii_index_in_di_library_index_to_library_name,offset)
			= from_string offset buffer;
		#! (litlii_used_by_code,offset)
			= from_string offset buffer;
		#! (litlii_used_by_type,offset)
			= from_string offset buffer;
						
		#! di
			= { default_elem &
				litlii_index_in_di_library_index_to_library_name	= litlii_index_in_di_library_index_to_library_name
			,	litlii_used_by_code									= litlii_used_by_code
			,	litlii_used_by_type									= litlii_used_by_type
			};
		= (di,offset);	
};

:: LazyTypeReference
	= {
		ltr_lazy_dynamic_index	:: !Int		// within main dynamic (on disk)
	,	ltr_library_instance_i	:: !Int		// relative from the lazy dynamic (on disk)
	};
	
	// Maybe
/*
::	Maybe x
	=	Just x
	|	Nothing

*/

ENDECODE_MAYBE_SIZE	:== 1;
ENDECODE_JUST	 	:== 0;
ENDECODE_NOTHING	:== 1;

instance EnDecode (Maybe m) | EnDecode m
where {
	to_size (Just i)
		= ENDECODE_MAYBE_SIZE + to_size i;
	to_size Nothing
		= ENDECODE_MAYBE_SIZE;
	
	to_string x=:(Just i) offset buffer 	
		# buffer
			= { buffer & [offset] = toChar ENDECODE_JUST };
		# (offset,buffer)
			= to_string i (offset + ENDECODE_MAYBE_SIZE) buffer;
		= (offset,buffer);		

	to_string Nothing offset buffer 	
		# buffer
			= { buffer & [offset] = toChar ENDECODE_NOTHING };
		# offset
			= offset + ENDECODE_MAYBE_SIZE;
		= (offset,buffer);
	
	from_string offset buffer	
		# disk_type_reference_id
			= toInt (buffer.[offset]);
		| disk_type_reference_id == ENDECODE_JUST
			#! (x,offset)
				= from_string (offset + ENDECODE_MAYBE_SIZE) buffer;
			#! x = Just x
			= (x, offset);
		| disk_type_reference_id == ENDECODE_NOTHING
			#! x = Nothing
			# offset
				= offset + ENDECODE_MAYBE_SIZE;
			= (x, offset);
};

/*
:: LazyTypeReference
	= {
		ltr_lazy_dynamic_index	:: !Int		// within main dynamic (on disk)
	,	ltr_library_instance_i	:: !Int		// relative from the lazy dynamic (on disk)
	};
*/

instance EnDecode LazyTypeReference
where {
	to_size {ltr_lazy_dynamic_index,ltr_library_instance_i}
		= to_size ltr_lazy_dynamic_index + to_size ltr_library_instance_i;

	to_string {ltr_lazy_dynamic_index,ltr_library_instance_i} offset buffer
		# (offset,buffer)
			= to_string ltr_lazy_dynamic_index offset buffer;
		# (offset,buffer)
			= to_string ltr_library_instance_i offset buffer;
		= (offset,buffer);

	from_string offset buffer
		#! (ltr_lazy_dynamic_index,offset)
			= from_string offset buffer;
		#! (ltr_library_instance_i,offset)
			= from_string offset buffer;
			
		#! di
			= { default_elem &
				ltr_lazy_dynamic_index		= ltr_lazy_dynamic_index
			,	ltr_library_instance_i		= ltr_library_instance_i
			};
		= (di,offset);	
};

instance DefaultElem (Maybe m)
where {
	default_elem
		= Nothing;
};

instance DefaultElem LazyTypeReference
where {
	default_elem
		= {
			ltr_lazy_dynamic_index	= 0
		,	ltr_library_instance_i	= 0
		};			

};