J
jacob navia
Specifications
--------------
Add
int (*Add)(List *l,const void *data);
int (*Add)(TYPEList *l, TYPE data);
Description:
Adds the given element to the container. In its generic form it is
assumed that ”data” points to a contiguous memory area of at least
ElementSize bytes. Inits specialized form the data is passed by value.
Returns a value greater than zero if the addition of the element to the
list completed successfully, a negative error code otherwise.
Errors:
CONTAINER ERROR BADARG The list or the data pointers are NULL .
CONTAINER ERROR READONLY The list is read-only. No modifications allowed.
CONTAINER ERROR NOMEMORY Not enough memory to complete the operation.
Invariants: The input data is not modified.
Returns:
A positive number if the element was added or a negative error code
otherwise.
Example:
/* This example shows how to:
(1) Create a linked list of "double" data
(2) Fill it using the "Add" function
(3) Print it using the GetElement function */
#include <containers.h>
static void PrintList(List *AL)
{
size_t i;
for (i=0; i<iList.Size(AL);i++) {
printf("%g ",*(double *)iList.GetElement(AL,i));
}
printf("\n");
}
static void FillList(List * AL,size_t siz)
{
size_t i;
for (i=0; i<siz;i++) {
double d = i;
iList.Add(AL,&d);
}
}
int main(void)
{
List *AL = iList.Create(sizeof(double));
FillList(AL,10);
PrintList(AL);
return 0;
}
OUTPUT: 0123456789
------------------------------------------------------------------------------------
Implementation
--------------
Add
/* Add without error checking (nd for no debug) */
1 static int Add_nd(List *l,void *elem)
2 {
3 list_element *newl;
4 newl = new_link(l,elem,"iList.Add");
5 if (newl == 0)
6 return CONTAINER_ERROR_NOMEMORY;
7 if (l->count == 0) {
8 l->First = newl;
10 }
11 else {
12 l->Last->Next = newl;
13 }
14 l->Last = newl;
15 l->timestamp++;
16 ++l->count;
17 return
18 }
19
20 static int Add(List *l,void *elem)
21 {
22 int r;
23 if (l == NULL || elem == NULL) return NullPtrError("Add");
24 if (l->Flags &CONTAINER_READONLY) return ErrorReadOnly(l,"Add");
25 r = Add_nd(l,elem);
26 if (r && (l->Flags & CONTAINER_HAS_OBSERVER))
27 iObserver.Notify(l,CCL_ADD,elem,NULL);
28 return r;
29 }
This function adds one element at the end. The Add entry point performs
the error checking and calls Add_nd an internal function that does the
actual work. This is needed because other functions call internally Add
after they have already performed the error checking.
The Add_nd function requests a new list element (line 4). If that
succeeds the new element must be inserted in the list. If the list is
empty it just establishes the start of the list (8), if not, it adds it
after the last element (12). The new list element is the last one (14).
Errors leave the list unchanged. Exclusive access to the list is needed
between the line 8 and the line 16 in the code. This operation is a
modification of the list, and it needs to update the timestamp value to
notify possible iterators that they are invalid.
If the Add_nd function was successful and this container has a
registered observer we notify the observer of this event.
AddRange
1 static int AddRange(List * AL,size_t n, void *data)
2 {
3 unsigned char *p;
4 list_element *oldLast;
5
6 if (AL == NULL) return NullPtrError("AddRange");
7 if (AL->Flags & CONTAINER_READONLY) {
8 AL->RaiseError("iList.AddRange",CONTAINER_ERROR_READONLY);
9 return CONTAINER_ERROR_READONLY;
10 }
11 if (n == 0) return 0;
12 if (data == NULL) {
13 AL->RaiseError("iList.AddRange",CONTAINER_ERROR_BADARG);
14 return CONTAINER_ERROR_BADARG;
15 }
16 p = data;
17 oldLast = AL->Last; while(n>0){
18 int r = Add_nd(AL,p);
19 if (r < 0) {
20 AL->Last = oldLast;
21 if (AL->Last) {
22 list_element *removed = oldLast->Next;
23 while (removed) {
24 list_element *tmp = removed->Next;
25 if (AL->Heap)
26 iHeap.FreeObject(AL->Heap,removed);
27
28 else AL->Allocator->free(removed);
29 removed = tmp;
30 }
31 AL->Last->Next = NULL;
32 }
33 return r;
34 }
35 p += AL->ElementSize; /* Point to the next element */
36 n--; /* Count the items added so far */
37 }
38 AL->timestamp++;
39 if (AL->Flags & CONTAINER_HAS_OBSERVER)
40 iObserver.Notify(AL,CCL_ADDRANGE,data,(void *)n);
41 return 1;
42 }
This function calls repeatedly Add_nd for each element of the given
array. Any error provokes an abort and the original list is left
unchanged.
Error checking is done in lines 6 to 15, testing for NULL for the list
and the data. If the number of elements is zero the function does
nothing and returns zero. The code accepts data as NULL if the number of
elements is zero. If n is zero this code still checks that the list is
not NULL , and that the list is not read only, considering both to be
errors. Nothing is specified for those cases and you can’t rely on this
behavior for other implementations.
Note that at compile time we do not know the size of each element and we
can’t index into this array. We just setup a generic pointer to the
start of the data area (16), and increment it by the size of each
element at each iteration (line 35). This implementation supposes that
the size of the elements as assumed by the list is the same as the size
of the element as assumed by the calling program.
If an error occurs when adding elements the new elements are discarded,
the list is reset to its previous state and an error code is returned.
(lines 20-33). The eventually added elements are discarded (lines 24-30).
Notes:
It would be far more efficient to test at the start of the loop if there
is enough space for the n list elements than doing it within the loop.
That would eliminate the code for reclaiming the already allocated
items. This isn’t done because the list allocator could be the default
malloc function that doesn’t allow queries of this type.
--------------
Add
int (*Add)(List *l,const void *data);
int (*Add)(TYPEList *l, TYPE data);
Description:
Adds the given element to the container. In its generic form it is
assumed that ”data” points to a contiguous memory area of at least
ElementSize bytes. Inits specialized form the data is passed by value.
Returns a value greater than zero if the addition of the element to the
list completed successfully, a negative error code otherwise.
Errors:
CONTAINER ERROR BADARG The list or the data pointers are NULL .
CONTAINER ERROR READONLY The list is read-only. No modifications allowed.
CONTAINER ERROR NOMEMORY Not enough memory to complete the operation.
Invariants: The input data is not modified.
Returns:
A positive number if the element was added or a negative error code
otherwise.
Example:
/* This example shows how to:
(1) Create a linked list of "double" data
(2) Fill it using the "Add" function
(3) Print it using the GetElement function */
#include <containers.h>
static void PrintList(List *AL)
{
size_t i;
for (i=0; i<iList.Size(AL);i++) {
printf("%g ",*(double *)iList.GetElement(AL,i));
}
printf("\n");
}
static void FillList(List * AL,size_t siz)
{
size_t i;
for (i=0; i<siz;i++) {
double d = i;
iList.Add(AL,&d);
}
}
int main(void)
{
List *AL = iList.Create(sizeof(double));
FillList(AL,10);
PrintList(AL);
return 0;
}
OUTPUT: 0123456789
------------------------------------------------------------------------------------
Implementation
--------------
Add
/* Add without error checking (nd for no debug) */
1 static int Add_nd(List *l,void *elem)
2 {
3 list_element *newl;
4 newl = new_link(l,elem,"iList.Add");
5 if (newl == 0)
6 return CONTAINER_ERROR_NOMEMORY;
7 if (l->count == 0) {
8 l->First = newl;
10 }
11 else {
12 l->Last->Next = newl;
13 }
14 l->Last = newl;
15 l->timestamp++;
16 ++l->count;
17 return
18 }
19
20 static int Add(List *l,void *elem)
21 {
22 int r;
23 if (l == NULL || elem == NULL) return NullPtrError("Add");
24 if (l->Flags &CONTAINER_READONLY) return ErrorReadOnly(l,"Add");
25 r = Add_nd(l,elem);
26 if (r && (l->Flags & CONTAINER_HAS_OBSERVER))
27 iObserver.Notify(l,CCL_ADD,elem,NULL);
28 return r;
29 }
This function adds one element at the end. The Add entry point performs
the error checking and calls Add_nd an internal function that does the
actual work. This is needed because other functions call internally Add
after they have already performed the error checking.
The Add_nd function requests a new list element (line 4). If that
succeeds the new element must be inserted in the list. If the list is
empty it just establishes the start of the list (8), if not, it adds it
after the last element (12). The new list element is the last one (14).
Errors leave the list unchanged. Exclusive access to the list is needed
between the line 8 and the line 16 in the code. This operation is a
modification of the list, and it needs to update the timestamp value to
notify possible iterators that they are invalid.
If the Add_nd function was successful and this container has a
registered observer we notify the observer of this event.
AddRange
1 static int AddRange(List * AL,size_t n, void *data)
2 {
3 unsigned char *p;
4 list_element *oldLast;
5
6 if (AL == NULL) return NullPtrError("AddRange");
7 if (AL->Flags & CONTAINER_READONLY) {
8 AL->RaiseError("iList.AddRange",CONTAINER_ERROR_READONLY);
9 return CONTAINER_ERROR_READONLY;
10 }
11 if (n == 0) return 0;
12 if (data == NULL) {
13 AL->RaiseError("iList.AddRange",CONTAINER_ERROR_BADARG);
14 return CONTAINER_ERROR_BADARG;
15 }
16 p = data;
17 oldLast = AL->Last; while(n>0){
18 int r = Add_nd(AL,p);
19 if (r < 0) {
20 AL->Last = oldLast;
21 if (AL->Last) {
22 list_element *removed = oldLast->Next;
23 while (removed) {
24 list_element *tmp = removed->Next;
25 if (AL->Heap)
26 iHeap.FreeObject(AL->Heap,removed);
27
28 else AL->Allocator->free(removed);
29 removed = tmp;
30 }
31 AL->Last->Next = NULL;
32 }
33 return r;
34 }
35 p += AL->ElementSize; /* Point to the next element */
36 n--; /* Count the items added so far */
37 }
38 AL->timestamp++;
39 if (AL->Flags & CONTAINER_HAS_OBSERVER)
40 iObserver.Notify(AL,CCL_ADDRANGE,data,(void *)n);
41 return 1;
42 }
This function calls repeatedly Add_nd for each element of the given
array. Any error provokes an abort and the original list is left
unchanged.
Error checking is done in lines 6 to 15, testing for NULL for the list
and the data. If the number of elements is zero the function does
nothing and returns zero. The code accepts data as NULL if the number of
elements is zero. If n is zero this code still checks that the list is
not NULL , and that the list is not read only, considering both to be
errors. Nothing is specified for those cases and you can’t rely on this
behavior for other implementations.
Note that at compile time we do not know the size of each element and we
can’t index into this array. We just setup a generic pointer to the
start of the data area (16), and increment it by the size of each
element at each iteration (line 35). This implementation supposes that
the size of the elements as assumed by the list is the same as the size
of the element as assumed by the calling program.
If an error occurs when adding elements the new elements are discarded,
the list is reset to its previous state and an error code is returned.
(lines 20-33). The eventually added elements are discarded (lines 24-30).
Notes:
It would be far more efficient to test at the start of the loop if there
is enough space for the n list elements than doing it within the loop.
That would eliminate the code for reclaiming the already allocated
items. This isn’t done because the list allocator could be the default
malloc function that doesn’t allow queries of this type.