Next: , Previous: objects pairs, Up: objects


12.7 Bytevector objects

Bytevectors are blocks of memory referenced by machine words tagged as bytevectors. The first word in the memory block is a fixnum representing the number of bytes in the data area; a bytevector is capable of holding at most a number of bytes equal to the return value of greatest-fixnum.

When allocating a bytevector capable of holding N bytes, the actual size of the allocated data area is N+1; the additional last byte is not part of the data area and is perpetually set to zero. All Vicare's functions operating on bytevectors set to zero the byte right after the last used one in the data area. This last byte allows every bytevector to be used as ASCIIZ string at the C language level.

To allow for the same binary layout on both 32-bit and 64-bit platforms, the data area starts 8 bytes after the beginning; on a 32-bit platform the layout is:

       1st word   2nd word                       last byte
     |----------|----------|-------------------|-----------|
        length     unused        data area      set to zero

on a 64-bit platform the layout is:

            1st word                             last byte
     |---------------------|-------------------|-----------|
            length               data area      set to zero
Basic operations

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

     ikpcb * pcb        = ik_the_pcb();
     long    bv_len     = the_number_of_bytes;
     long    block_size = disp_bytevector_data + bv_len + 1;
     lont    align_size = IK_ALIGN(block_size);
     ikptr   bv = ik_safe_alloc(pcb, align_size) | bytevector_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 bytevector tag (an integer value fitting in 3 bits) which allows to recognise bytevectors among all the other built in objects.

We have to explicitly store the bytevector length in the memory block as a fixnum and set the last byte to zero, so usually a full allocation looks like this:

     ikptr
     ika_bytevector_alloc (ikpcb * pcb, long bv_len)
     {
       long   align_size;
       ikptr  s_bv;
       char * data;
       align_size = IK_ALIGN(disp_bytevector_data + bv_len + 1);
       s_bv       = ik_safe_alloc(pcb, align_size)
                    | bytevector_tag;
       IK_REF(s_bv, off_bytevector_length) = IK_FIX(bv_len);
       data = (char *)(long)(s_bv + off_bytevector_data);
       data[bv_len] = '\0';
       return s_bv;
     }

to acquire the number of bytes we do:

     ikptr  s_bv = the_bytevector;
     long   bv_len;
     
     bv_len = IK_UNFIX(IK_REF(s_bv, off_bytevector_length));

and to access the data area we do:

     ikptr      s_bv = the_bytevector;
     uint8_t *  data_area;
     
     data_area = (uint8_t *)(long)(s_bv + off_bytevector_data);
— Preprocessor Symbol: bytevector_tag

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

— Preprocessor Symbol: disp_bytevector_length

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

— Preprocessor Symbol: disp_bytevector_data

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

— Preprocessor Symbol: off_bytevector_length

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

— Preprocessor Symbol: off_bytevector_data

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

Notice that on both 32-bit and 64-bit platforms: the first byte of the data area is at the same byte offset from the first byte of the bytevector memory block.

Convenience preprocessor macros
— Function: Preprocessor Macro IK_IS_BYTEVECTOR (ikptr obj)

Evaluate to true if obj is a bytevector.

— Preprocessor Macro: long IK_BYTEVECTOR_LENGTH (ikptr bv)

Return the number of bytes in the data area of bv.

— Preprocessor Macro: ikptr IK_BYTEVECTOR_LENGTH_FX (ikptr bv)

Return a fixnum representing the number of bytes in the data area of bv.

— Preprocessor Macro: long IK_BYTEVECTOR_DATA (ikptr bv)

Return a integer representing the memory address of the first byte in the data area of bv.

— Preprocessor Macro: void * IK_BYTEVECTOR_DATA_VOIDP (ikptr bv)
— Preprocessor Macro: char * IK_BYTEVECTOR_DATA_CHARP (ikptr bv)
— Preprocessor Macro: uint8_t * IK_BYTEVECTOR_DATA_UINT8P (ikptr bv)

Return a pointer referencing the first byte in the data area of bv.

Operations on bytevectors
— Function: ikptr ika_bytevector_alloc (ikpcb * pcb, long requested_number_of_bytes)

Allocate, initialise and return a new bytevector capable of holding the specified number of bytes. The contents of the data area are unspecified. The requested bytevector length must be in the range of fixnums.

— Function: ikptr ika_bytevector_from_cstring (ikpcb * pcb, const char * cstr)

Allocate, initialise and return a new bytevector and copy the contents of the ASCIIZ string referenced by cstr in the data area.

NOTE If the string length is greater than the maximum positive fixnum: the string is silently truncated to a length equal to the maximum positive fixnum.

— Function: ikptr ika_bytevector_from_cstring_len (ikpcb * pcb, const char * cstr, size_t len)

Allocate, initialise and return a new bytevector and copy the len bytes of the ASCII string referenced by cstr in the data area.

NOTE If the string length is greater than the maximum positive fixnum: the string is silently truncated to a length equal to the maximum positive fixnum.

— Function: ikptr ika_bytevector_from_memory_block (ikpcb * pcb, const void * memory, size_t length)

Allocate, initialise and return a new bytevector and copy in the data area length bytes from of the memory block referenced by memory.

NOTE If the memory block length is greater than the maximum positive fixnum: the block is silently truncated to a length equal to the maximum positive fixnum.

— Function: ikptr ik_bytevector_from_utf16z (ikpcb * pcb, const void * data);

Build and return a new bytevector from a memory block referencing a UTF-16 string terminated with two consecutive zeros starting at even offset:

             char      char      char      char     0    0
          |----+----|----+----|----+----|----+----|----+----|
           byte byte byte byte byte byte byte byte byte byte

If the the end of the string is not found before the byte index reaches the maximum fixnum: return the false object.

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

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