Next: , Previous: objects bytevectors, Up: objects


12.8 Vector objects

Vectors are variable length blocks of memory referenced by machine words tagged as vectors. The first machine word of a vector block contains a fixnum representing the vector length; this means that the first word of a vector is tagged as a fixnum.

     |------------------------|-------------| reference to vector
           heap pointer         vector tag
     
     |------------------------|-------------| vector first word
          number of words       fixnum tag

After the length machine word comes the data area: an array of machine words, one for each vector slot; slot indexes are zero–based.

           0   1   2   3   4   5   6   7
     |---|---|---|---|---|---|---|---|---| vector memory block
       ^ |...............................|
       |        slots = data area
     length
     fixnum

A vector is capable of holding at most a number of values equal to the return value of greatest-fixnum. The fixnum representing the vector length, interpreted as raw signed integer, also represents the number of bytes in the data area.

A fixnum representing the index of slot N, interpreted as raw signed integer, also represents the offset in bytes of the firts byte of the slot with respect the beginning of the data area.

Basic operations

Vector objects are allocated on the heap; to perform the allocation we compute the whole size of the data area, add to it room for meta data and finally compute the aligned block size:

     ikpcb * pcb            = ik_the_pcb();
     long    length         = the_number_of_items;
     long    requested_size = wordsize * length;
     long    block_size     = disp_vector_data + requested_size;
     long    align_size     = IK_ALIGN(block_size);
     ikptr   vec = ik_safe_alloc(pcb, align_size) | vector_tag;

ik_safe_alloc() returns an ikptr value representing the aligned pointer, having the 3 least significant bits set to zero; we add to it the vector tag (an integer value fitting in 3 bits) which allows to recognise vectors among all the other built in objects.

We have to explicitly store the vector length in the memory block as a fixnum, so usually a full allocation looks like this:

     ikptr
     ika_vector_alloc (ikpcb * pcb, long number_of_items)
     {
       long  align_size;
       ikptr s_len;
       ikptr s_vec;
       s_len      = IK_FIX(number_of_items);
       align_size = IK_ALIGN(disp_vector_data + s_len);
       s_vec      = ik_safe_alloc(pcb, align_size) | vector_tag;
       IK_REF(s_vec, off_vector_length) = s_len;
       return s_vec;
     }

notice how we exploit the fact that the fixnum representing the number of elements equals the number of bytes in the data area needed to hold such elements.

The allocation operations described above leaves the data area uninitialised: its content is undefined. This is bad if the garbage collector moves the newly built vector before the elements are initialised to a correct Scheme value. The following function resets the data area to a vector of zero fixnums:

     ikptr
     ikrt_vector_clean (ikptr s_vec)
     {
       ikptr	s_len = IK_VECTOR_LENGTH_FX(s_vec);
       memset((char*)(long)(s_vec + off_vector_data), 0, s_len);
       return s_vec;
     }

To fill a vector of 3 items with fixnums we should do:

     ikptr  s_vec = the_vector;
     IK_REF(s_vec, off_vector_data + 0 * wordsize) = IK_FIX(10);
     IK_REF(s_vec, off_vector_data + 1 * wordsize) = IK_FIX(20);
     IK_REF(s_vec, off_vector_data + 2 * wordsize) = IK_FIX(30);

to retrieve the item at index 2 we do:

     ikptr  s_vec  = the_vector;
     ikptr  s_item = IK_REF(s_vec, off_vector_data + 2 * wordsize);

and to retrieve the vector length:

     ikptr  s_vec  = the_vector;
     ikptr  s_len  = IK_REF(s_vec, off_vector_length);
     long   length = IK_UNFIX(s_len);
— Preprocessor Symbol: vector_tag

An integer used to tag ikptr references to vector memory blocks.

— Preprocessor Symbol: disp_vector_length

Displacement of length. The number of bytes to add to an untagged pointer to vector to get the pointer to the first byte in the word holding the vector length as fixnum.

— Preprocessor Symbol: disp_vector_data

Displacement of data area. The number of bytes to add to an untagged pointer to vector to get the pointer to the first byte in the data area.

— Preprocessor Symbol: off_vector_length

An integer to add to a tagged ikptr reference to retrieve the pointer to the first byte of the vector length as fixnum.

— Preprocessor Symbol: off_vector_data

An integer to add to a tagged ikptr vector reference to retrieve the pointer to the first byte of the data area.

Convenience preprocessor macros
— Preprocessor Macro: ikptr IK_VECTOR_LENGTH_FX (ikptr vec)

Return a fixnum representing the number of items in the vector vec.

— Preprocessor Macro: long IK_VECTOR_LENGTH (ikptr vec)

Return an integer representing the number of items in the vector vec.

— Preprocessor Macro: ikptr IK_ITEM (ikptr vec, long idx)

Evaluate to the item at index idx in the vector vec. A use of this macro can appear both as operand and as left–side of an assignment; example:

          long    idx   = the_index;
          ikptr   s_vec = the_vector;
          ikptr   fx;
          
          IK_ITEM(s_vec, idx) = IK_FIX(10);
          fx = IK_ITEM(s_vec, idx);
Operations on vectors
— Function: ikptr ika_vector_alloc_no_init (ikpcb * pcb, long number_of_items)

Allocate, initialise and return a new vector object capable of holding the specified number of items. Leave the data area uninitialised.

— Function: ikptr ika_vector_alloc_and_init (ikpcb * pcb, long number_of_items)

Allocate, initialise and return a new vector object capable of holding the specified number of items. Initialise the data area so that all the items are set to the fixnum zero.

— Function: int ik_is_vector (ikptr vec)

Return true if vec is a reference to a vector object. This predicate tests that vec is tagged as vector reference and that the first machine word in the referenced memory block is a fixnum.

— Function: ikptr ikrt_vector_clean (ikptr vec)

Clean the data area so that all the items are set to the fixnum zero.

— Function: ikptr ikrt_vector_copy (ikptr dst, ikptr dst_start, ikptr src, ikptr src_start, ikptr count)

Copy count items from vector src starting at offset src_start, to vector dst starting at offset dst_start; src_start, dst_start and count must be non–negative fixnums. Return unspecified values.