Next: objects bytevectors, Previous: objects fixnums, Up: objects [Index]
A pair is a fixed–length block of memory composed of two machine words;
the 3 least significant bits of an ikptr_t
reference to a pair
are the pair tag.
|-------------------------|-------------| reference to pair heap pointer pair tag |-------------------|-------------------| pair memory block word 0 = car word 1 = cdr
The empty list is not a pair: it is a special constant fitting in a
single ikptr_t
machine word, and it is defined by the preprocessor
symbol IK_NULL_OBJECT
, shortly IK_NULL
.
Pairs are allocated as follows, leaving the car and cdr uninitialised:
ikpcb_t * pcb = ik_the_pcb(); ikptr_t s_pair = IKA_PAIR_ALLOC(pcb);
the car and cdr of a pair are extracted as follows:
ikptr_t s_pair = ...; ikptr_t s_car, s_cdr; s_car = IK_CAR(s_pair); s_cdr = IK_CDR(s_pair);
the car and cdr of a pair are set as follows:
ikpcb_t * pcb = ...; ikptr_t s_pair = ...; ikptr_t s_car = ...; ikptr_t s_cdr = ...; IK_CAR(s_pair) = s_car; IK_SIGNAL_DIRT(pcb, IK_CAR_PTR(s_pair)); IK_CDR(s_pair) = s_car; IK_SIGNAL_DIRT(pcb, IK_CDR_PTR(s_pair));
pair_mask
is the bit pattern used to isolate a pair tag from a
reference ikptr_t
; pair_tag
is the tag of ikptr_t
values
referencing a pair; pair_size
is the number of bytes in a pair
memory block on the heap.
disp_car
and disp_cdr
are the offsets in bytes of the car
and cdr from the beginning of a pair memory block; off_car
and
off_cdr
are integers to be added to a reference ikptr_t
tagged
as pair to retrieve the car and the cdr from a pair memory block.
Evaluate to true if the machine word X is tagged as pair.
Allocate a new pair object using ik_safe_alloc()
and return a
tagged reference to it. The pair words are left uninitialised.
Allocate a new pair object using ik_unsafe_alloc()
and return a
tagged reference to it. The pair words are left uninitialised.
Evaluate to the locations of the car and cdr of a pair; uses of these macros can appear both as operands and as left–side of assignments.
Evaluate to the pointers to the memory locations holding the car and cdr of a pair.
Return, respectively: the car of the car, the cdr of the car, the car of the cdr, the cdr of the cdr.
Evaluate to the pointers to the memory locations hokding the caar, cdar, cadr and cddr of the pair.
Allocate and return a new pair object using, respectively,
ik_safe_alloc()
and ik_unsafe_alloc()
and return a tagged
reference to it. Both the car and cdr are initialised to
IK_VOID_OBJECT
.
These functions do not call
ik_signal_dirt_in_page_of_pointer()
.
Return the length of the proper list referenced by list. Do not
handle circular lists. If the length exceeds LONG_MAX
: terminate
the process with ik_abort()
.
Given a reference list to a proper list of bytevectors, fill
argv with pointers to the data areas, setting the last element of
argv to NULL
. The array referenced by argv must be wide
enough to hold all the pointers from list plus the terminating
NULL
.
Given a reference list to a proper list of bytevectors: fill
argv with pointers to the data areas, setting the last element of
argv to NULL
; fill argc with the lengths of the
bytevectors. The array referenced by argv must be wide enough to
hold all the pointers from list plus the terminating NULL
; the
array referenced by argc must be wide enough to hold all the
lengths.
Given a pointer argv to a NULL
–terminated array of ASCIIZ
strings build and return a list of bytevectors holding a copy of the
ASCIIZ strings. Make use of pcb->root8
and pcb->root9
.
This function takes care of calling
ik_signal_dirt_in_page_of_pointer()
when appropriate.
Given a pointer argv to an array of ASCIIZ strings holding
argc pointers: build and return a list of bytevectors holding a
copy of the ASCIIZ strings. Make use of pcb->root8
and
pcb->root9
.
This function takes care of calling
ik_signal_dirt_in_page_of_pointer()
when appropriate.
The suggested general way to allocate and initialise a pair is as follows:
ikpcb_t * pcb = ...; ikptr_t s_pair; s_pair = ika_pair_alloc(pcb); pcb->root0 = &s_pair; { IK_ASS(IK_CAR(s_pair), ...); IK_SIGNAL_DIRT(pcb, IK_CAR_PTR(s_pair)); IK_ASS(IK_CDR(s_pair), ...); IK_SIGNAL_DIRT(pcb, IK_CDR_PTR(s_pair)); } pcb->root0 = NULL;
notice how we take care of allocating the new pair with a function that initialises the component words and of registering the pair as garbage collection root before calling the constructors for the car and cdr.
If the component words do not need memory allocation, for example because they are fixnums or already existing objects, we can use the faster code:
ikpcb_t * pcb = ik_the_pcb(); ikptr_t s_pair = IKA_PAIR_ALLOC(pcb); IK_CAR(s_pair) = IK_FIX(123); IK_CDR(s_pair) = IK_FIX(456);
Let’s say we need to build a list of bytevectors from ASCIIZ strings
in the array argv
and there are argc
of them:
ikpcb_t * pcb = ik_the_pcb(); char ** argv = ...; long argc = ...; ikptr_t s_list; if (argc) { ikptr_t s_spine; long i; s_list = s_spine = ika_pair_alloc(pcb); pcb->root0 = &s_list; pcb->root1 = &s_spine; { for (i=0; i<argc;) { IK_ASS(IK_CAR(s_spine), ika_bytevector_from_cstring(pcb, argv[i])); IK_SIGNAL_DIRT(pcb, IK_CAR_PTR(s_spine)); if (++i < argc) { IK_ASS(IK_CDR(s_spine), ika_pair_alloc(pcb)); IK_SIGNAL_DIRT(pcb, IK_CDR_PTR(s_spine)); s_spine = IK_CDR(s_spine); } else { IK_CDR(s_spine) = IK_NULL_OBJECT; break; } } } pcb->root1 = NULL; pcb->root0 = NULL; } else s_list = IK_NULL_OBJECT; /* make use of S_LIST */
Next: objects bytevectors, Previous: objects fixnums, Up: objects [Index]