A container library in C. Part 1: Header file

J

jacob navia

This is the first part of this posting. This is the header file
containers.h
--------------------------------------------------------cut here

#ifndef __containers_h__
#define __containers_h__
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
/*
A string collection is a table of zero terminated strings that will grow
automatically when you add elements to it.

As all other containers in this proposal, it uses an interface, i.e. a
table
of functions to provide the functionality and data access a string
collection
needs. Since the names of the functions are enclosed within the interface
structure we can use mnemonic names like Add, etc, without fear of
messing with
the user name space, and without adding lengthy prefixes.

Other advantage of an interface are the extensibility of it. You can add
functions of your own to the interface without interfering with the existing
ones. We will discuss this later when we discuss subclassing, but it is
obvious
that you can define a new interface that has the first members as the given
interface, but it has some extra members of your own.

*/

/* We define first an empty structure, that will be fully defined later,
to be
able to define the functions in our interface
*/
typedef struct _StringCollection StringCollection;
struct _StringEnumerator;

// Type definition of the compare function
typedef int (*CompareFunction)(void *elem1,void *elem2);

// Definition of the functions associated with this type.
typedef struct {
// Returns the number of elements stored
int (*GetCount)(StringCollection SC);

// Is this collection read only?
int (*IsReadOnly)(StringCollection SC);

// Sets this collection read-only or unsets the read-only flag
int (*SetReadOnly)(StringCollection SC,int flag);

// Adds one element at the end. Given string is copied
int (*Add)(StringCollection SC,char *newval);

// Adds a NULL terminated table of strings
int (*AddRange)(StringCollection SC,char **newvalues);

// Clears all data and frees the memory
int (*Clear)(StringCollection SC);

//Case sensitive search of a character string in the data
bool (*Contains)(StringCollection SC,char *str);

// Copies all strings into a NULL terminated vector
char **(*CopyTo)(StringCollection SC);

//Returns the index of the given string or -1 if not found
int (*IndexOf)(StringCollection SC,char *SearchedString);

// Inserts a string at the position zero.
int (*Insert)(StringCollection SC,char *);

// Inserts a string at the given position
int (*InsertAt)(StringCollection SC,int idx,char *newval);

// Returns the string at the given position
char *(*IndexAt)(StringCollection SC,int idx);

// Removes the given string if found
int (*Remove)(StringCollection SC,char *);

//Removes the string at the indicated position
int (*RemoveAt)(StringCollection SC,int idx);

// Frees the memory used by the collection
int (*Finalize)(StringCollection SC);

// Returns the current capacity of the collection
int (*GetCapacity)(StringCollection SC);

// Sets the capacity if there are no items in the collection
bool (*SetCapacity)(StringCollection SC,int newCapacity);

// Calls the given function for all strings. "Arg" is a used supplied
argument
// that can be NULL that is passed to the function to call
void (*Apply)(StringCollection SC,int (*Applyfn)(char *,void *
arg),void *arg);

// Calls the given function for each string and saves all results
// in an integer vector
int *(*Map)(StringCollection SC,int (*Applyfn)(char *));

// Pushes a string, using the collection as a stack
int (*Push)(StringCollection SC,char *str);

// Pops the last string off the collection
char * (*Pop)(StringCollection SC);

// Replaces the character string at the given position with a new one
char *(*ReplaceAt)(StringCollection SC,int idx,char *newval);

// Returns whether the collection makes case sensitive comparisons or not
int (*IsCaseSensitive)(StringCollection SC);

// Sets case sensitivity by comparisons
int (*SetCaseSensitive)(StringCollection SC,int newval);

// Compares two string collections
bool (*Equal)(StringCollection SC1,StringCollection SC2);

// Copy a string collection
StringCollection (*Copy)(StringCollection SC);
} StringCollectionInterface;
/*
Note that this lengthy structure is not replicated at each string collection
object. Each string collection holds just a pointer to it, spending only
sizeof(void *) bytes.
*/


// Definition of the String Collection type
struct _StringCollection {
StringCollectionInterface *lpVtbl; // The table of functions
int count; /* in element size units */
char **contents; /* The contents of the collection */
int capacity; /* in element_size units */
unsigned int flags; // Read-only or other flags
};

struct _StringEnumerator;
typedef struct _StringEnumeratorFunctions {
int (*Next)(struct _StringEnumerator *);
int (*Previous)(struct _StringEnumerator *);
char *(*GetCurrent)(struct _StringEnumerator *);
int (*SetCurrent)(struct _StringEnumerator *,int);
} StringEnumeratorFunctions;

typedef struct _StringEnumerator {
StringEnumeratorFunctions *lpVtbl;
StringCollection SC;
int CurrentIndex;
} StringEnumerator;

// This are the only exported functions from this module
StringCollection newStringCollection(int startsize);
#if 0
char *operator[](StringCollection *,int);
char *operator[]=(StringCollection SC,int idx,char *newval);
#endif
/* ------------------------------------------------------------------------
* LIST Interface
*
* This describes the single linked list data structure functions
*
* Each list objects has a list composed of list elemants.
*

*-------------------------------------------------------------------------*/
typedef struct _list_element {
struct _list_element *Next;
char Data[];
} list_element;

typedef struct _List List;
typedef struct {
// Returns the number of elements stored
int (*GetCount)(List AL);

// Is this collection read only?
int (*IsReadOnly)(List AL);

// Sets this collection read-only or unsets the read-only flag
int (*SetReadOnly)(List AL,int flag);

// Adds one element at the end. Given element is copied
int (*Add)(List AL,void *newval);

// Clears all data and frees the memory
int (*Clear)(List AL);

//Case sensitive search of a character string in the data
bool (*Contains)(List AL,void *str);

// Copies all strings into a NULL terminated vector
List (*Copy)(List AL);

//Returns the index of the given string or -1 if not found
int (*IndexOf)(List AL,void *SearchedElement);

// Inserts a value at the position zero.
int (*Insert)(List AL,void *);

// Inserts a value at the given position
int (*InsertAt)(List AL,int idx,void *newval);

// Returns the list at the given position
void *(*IndexAt)(List AL,int idx);

// Removes the given string if found
int (*Remove)(List AL,void *);

//Removes the string at the indicated position
int (*RemoveAt)(List AL,int idx);

// Frees the memory used by the collection
int (*Finalize)(List AL);

// Pushes a string, using the collection as a stack
int (*Push)(List AL,void *str);

// Pops the last string off the list
list_element * (*Pop)(List AL);

// Replaces the character string at the given position with a
new one
void *(*ReplaceAt)(List AL,int idx,void *newval);

// Sorts the list
List (*Sort)(List l,int (*compar)(const void *,const void *));

// Reverses the list
List (*Reverse)(List l);

// Gets an element range from the list
List (*GetRange)(List l,int start,int end);

// Compares two list (Shallow comparison)
bool (*Equal)(List l1,List l2);

// Add a list at the end of another
List (*Append)(List l1,List l2);

// Comparison function
int (*CompareFn)(void * elem1, void *elem2);

// Set The comparison function
CompareFunction (*SetCompareFunction)(List l,CompareFunction fn);
} ListInterface;

struct _List {
ListInterface *lpVtbl;
size_t ElementSize;
int count; /* in elements units */
list_element *Last; /* The last item */
list_element *First; /* The contents of the list start
here */
unsigned Flags;
};
List newList(int element_size);
#if 0
list_element * operator[]=(List &l,size_t position,void *data);
list_element * operator[](List &l,int position);
#endif
/*-------------------------------------------------------------------------
* inline functions

*------------------------------------------------------------------------*/
list_element *inline GetFirst(List *l)
{
return l->First;
}
list_element * inline GetNext(list_element *l)
{
return l->Next;
}

list_element * inline GetLast(List *l)
{
return l->Last;
}

/*****************************************************************************
*
*
* The array list
*
* We have now a general framework for handling string collections.
Looking
* at the code, it is easy to see that with a little effort, we could
make
* this much more general if we would replace the strings with a fixed
size
* object, that can be any data structure. This general container is
present
* in other languages like C#, where it is called ArrayList. You can
store
* in an ArrayList anything, in C# it is not even required that the
objects
* stored inside should be of the same type.

* Since the nature of the objects stored is not known to the container,
* it is necessary to cast the result of an ArrayList into the final type
* that the user knows it is in there. In C# this is the object, the root
* of the object hierarchy, in C it is the void pointer, a pointer
that can
* point to any kind of object.

* If we look at the code of one of the string collection functions we
can
* see the following:
* static char *IndexAt(struct _StringCollection *SC,int idx)
* {
* if (idx >=SC.count || idx < 0)
* return NULL;
* return SC.contents[idx];
* }

* We can easily generalize this to a container by changing the char
pointer
* result declaration to just a void pointer.


****************************************************************************/

// Forward declaration of the string collection type
typedef struct _ArrayList ArrayList;

// Definition of the functions associated with this type.
typedef struct {
// Returns the number of elements stored
int (*GetCount)(ArrayList *AL);

// Is this collection read only?
int (*IsReadOnly)(ArrayList *AL);

// Sets this collection read-only or unsets the read-only flag
int (*SetReadOnly)(ArrayList *AL,int flag);

// Adds one element at the end. Given element is copied
int (*Add)(ArrayList *AL,void *newval);

// Adds a NULL terminated table of strings
int (*AddRange)(ArrayList *AL,void **newvalues);

// Clears all data and frees the memory
int (*Clear)(ArrayList *AL);

//Case sensitive search of a character string in the data
bool (*Contains)(ArrayList *AL,void *str);

// Copies all strings into a NULL terminated vector
void **(*CopyTo)(ArrayList *AL);

//Returns the index of the given string or -1 if not found
int (*IndexOf)(ArrayList *AL,void *SearchedString);

// Inserts a string at the position zero.
int (*Insert)(ArrayList *AL,void *);

// Inserts a string at the given position
int (*InsertAt)(ArrayList *AL,int idx,void *newval);

// Returns the string at the given position
void *(*IndexAt)(ArrayList *AL,int idx);

// Removes the given string if found
int (*Remove)(ArrayList *AL,void *);

//Removes the string at the indicated position
int (*RemoveAt)(ArrayList *AL,int idx);

// Frees the memory used by the collection
int (*Finalize)(ArrayList *AL);

// Returns the current capacity of the collection
int (*GetCapacity)(ArrayList *AL);

// Sets the capacity if there are no items in the collection
bool (*SetCapacity)(ArrayList *AL,int newCapacity);

// Calls the given function for all strings. "Arg" is a used supplied
argument
// that can be NULL that is passed to the function to call
void (*Apply)(ArrayList *AL,int (*Applyfn)(void *,void * arg),void *arg);

// Pushes a string, using the collection as a stack
int (*Push)(ArrayList *AL,void *str);

// Pops the last string off the collection
void * (*Pop)(ArrayList *AL);

// Replaces the character string at the given position with a new one
void *(*ReplaceAt)(ArrayList *AL,int idx,void *newval);

} ArrayListInterface;

// Definition of the String Collection type
struct _ArrayList {
ArrayListInterface *lpVtbl; // The table of functions
int count; /* number of elements in the array */
void **contents; /* The contents of the collection */
int capacity; /* allocated space in the contents
vector */
unsigned int flags; // Read-only or other flags
size_t ElementSize; // Size of the elements stored in this array.
};

// This are the only exported functions from this module
ArrayList newArrayList(size_t elementsize,int startsize);
#if 0
void *operator[](ArrayList AL,int idx);
void *operator[]=(ArrayList AL,int idx,void *newval);
#endif
//******************************************************************************
//
// ErrorHandling
//
//******************************************************************************
#define CONTAINER_ERROR_BADARG (0x80070057)
#define CONTAINER_ERROR_NOMEMORY (0x8007000E)
#define CONTAINER_ERROR_INDEX -3
#define CONTAINER_ERROR_READONLY -4
#define CONTAINER_ERROR_FILEOPEN -5
void ContainerRaiseError(char *fnname,unsigned errorcode);
#endif
 
D

David RF

[...]

Hi Jacob,

1.
With gcc ...

david@debian:~$ gcc -std=c89 -o demo demo.c
demo.c:36: error: expected identifier or ‘(’ before ‘/’ token
demo.c:39: error: expected identifier or ‘(’ before ‘/’ token
demo.c:120: warning: data definition has no type or storage class
demo.c:128: error: expected identifier or ‘(’ before ‘/’ token
demo.c:149: error: field ‘SC’ has incomplete type
demo.c:154: error: expected identifier or ‘(’ before ‘/’ token
demo.c:177: error: expected specifier-qualifier-list before ‘/’ token
demo.c:270: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’
before ‘GetFirst’
demo.c:275: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’
before ‘GetNext’
demo.c:281: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’
before ‘GetLast’
demo.c:329: error: expected identifier or ‘(’ before ‘/’ token
demo.c:332: error: expected identifier or ‘(’ before ‘/’ token
demo.c:398: warning: data definition has no type or storage class
demo.c:400: error: expected identifier or ‘(’ before ‘/’ token
demo.c:412: error: expected identifier or ‘(’ before ‘/’ token
demo.c:418: error: expected identifier or ‘(’ before ‘/’ token
demo.c:418:2: error: unterminated comment
demo.c:1:1: error: unterminated #ifndef

david@debian:~$ gcc -std=c99 -o demo demo.c
demo.c:270: error: expected identifier or ‘(’ before ‘inline’
demo.c:275: error: expected identifier or ‘(’ before ‘inline’
demo.c:281: error: expected identifier or ‘(’ before ‘inline’

sugest
inline list_element *GetFirst(List *l)
inline list_element *GetNext(list_element *l)
inline list_element *GetLast(List *l)
instead of
list_element *inline GetFirst(List *l)
list_element * inline GetNext(list_element *l)
list_element * inline GetLast(List *l)


2.
#ifndef __containers_h__
struct _List {
....
An initial underscore should not be used for any user-created names
 
J

jacob navia

David RF a écrit :
[...]

Hi Jacob,

1.
With gcc ...

david@debian:~$ gcc -std=c89 -o demo demo.c
demo.c:36: error: expected identifier or ‘(’ before ‘/’ token
demo.c:39: error: expected identifier or ‘(’ before ‘/’ token
demo.c:120: warning: data definition has no type or storage class
demo.c:128: error: expected identifier or ‘(’ before ‘/’ token
demo.c:149: error: field ‘SC’ has incomplete type
demo.c:154: error: expected identifier or ‘(’ before ‘/’ token
demo.c:177: error: expected specifier-qualifier-list before ‘/’ token
demo.c:270: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’
before ‘GetFirst’
demo.c:275: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’
before ‘GetNext’
demo.c:281: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’
before ‘GetLast’
demo.c:329: error: expected identifier or ‘(’ before ‘/’ token
demo.c:332: error: expected identifier or ‘(’ before ‘/’ token
demo.c:398: warning: data definition has no type or storage class
demo.c:400: error: expected identifier or ‘(’ before ‘/’ token
demo.c:412: error: expected identifier or ‘(’ before ‘/’ token
demo.c:418: error: expected identifier or ‘(’ before ‘/’ token
demo.c:418:2: error: unterminated comment
demo.c:1:1: error: unterminated #ifndef

The program is written in standard C. Please use a standard C compiler.
david@debian:~$ gcc -std=c99 -o demo demo.c
^^^^^^^^

better

:)
demo.c:270: error: expected identifier or ‘(’ before ‘inline’
demo.c:275: error: expected identifier or ‘(’ before ‘inline’
demo.c:281: error: expected identifier or ‘(’ before ‘inline’

OK, lcc-win accepts inline as written. It should be changed, I did not realize that.
sugest
inline list_element *GetFirst(List *l)
inline list_element *GetNext(list_element *l)
inline list_element *GetLast(List *l)
instead of
list_element *inline GetFirst(List *l)
list_element * inline GetNext(list_element *l)
list_element * inline GetLast(List *l)


OK


2.
#ifndef __containers_h__
struct _List {
...
An initial underscore should not be used for any user-created names

That is why the underscore is there!
To avoid using the user's name space. Remember, the container library should be
part of the implementation.
 
B

bartc

jacob navia said:
David RF a écrit :
The program is written in standard C. Please use a standard C compiler.


OK, lcc-win accepts inline as written. It should be changed, I did not
realize that.

Have you ever thought of trying this stuff with other compilers? Just for a
second opinion?

My first problems were with the // comments wrapping (it would convenient to
wrap-proof such comments, for serious bits of code like this, by converting
//.... to /*....*/, as such problems are not going to improve the
dispositions of any critics)

Then my gcc (3.4.5 mingw) didn't like the function declarations (with or
without the c99 switch), saying "warning: parameter has incomplete type",
starting from line 42 (obviously).
 
J

jacob navia

Sorry, I have mixed up things when transferring to the
email sofwtare. Here is an updated version, compatible with gcc

#ifndef __containers_h__
#define __containers_h__
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#ifndef __LCC__
#define NO_GC
#define bool int
#define true 1
#define false 0
#endif
/*
A string collection is a table of zero terminated strings that will grow
automatically when you add elements to it.

As all other containers in this proposal, it uses an interface, i.e. a table
of functions to provide the functionality and data access a string collection
needs. Since the names of the functions are enclosed within the interface
structure we can use mnemonic names like Add, etc, without fear of messing with
the user name space, and without adding lengthy prefixes.

Other advantage of an interface are the extensibility of it. You can add
functions of your own to the interface without interfering with the existing
ones. We will discuss this later when we discuss subclassing, but it is obvious
that you can define a new interface that has the first members as the given
interface, but it has some extra members of your own.

*/

/* We define first an empty structure, that will be fully defined later, to be
able to define the functions in our interface
*/
typedef struct _StringCollection StringCollection;
struct _StringEnumerator;

// Type definition of the compare function
typedef int (*CompareFunction)(void *elem1,void *elem2);

// Definition of the functions associated with this type.
typedef struct {
// Returns the number of elements stored
int (*GetCount)(StringCollection SC);

// Is this collection read only?
int (*IsReadOnly)(StringCollection SC);

// Sets this collection read-only or unsets the read-only flag
int (*SetReadOnly)(StringCollection SC,int flag);

// Adds one element at the end. Given string is copied
int (*Add)(StringCollection SC,char *newval);

// Adds a NULL terminated table of strings
int (*AddRange)(StringCollection SC,char **newvalues);

// Clears all data and frees the memory
int (*Clear)(StringCollection SC);

//Case sensitive search of a character string in the data
bool (*Contains)(StringCollection SC,char *str);

// Copies all strings into a NULL terminated vector
char **(*CopyTo)(StringCollection SC);

//Returns the index of the given string or -1 if not found
int (*IndexOf)(StringCollection SC,char *SearchedString);

// Inserts a string at the position zero.
int (*Insert)(StringCollection SC,char *);

// Inserts a string at the given position
int (*InsertAt)(StringCollection SC,int idx,char *newval);

// Returns the string at the given position
char *(*IndexAt)(StringCollection SC,int idx);

// Removes the given string if found
int (*Remove)(StringCollection SC,char *);

//Removes the string at the indicated position
int (*RemoveAt)(StringCollection SC,int idx);

// Frees the memory used by the collection
int (*Finalize)(StringCollection SC);

// Returns the current capacity of the collection
int (*GetCapacity)(StringCollection SC);

// Sets the capacity if there are no items in the collection
bool (*SetCapacity)(StringCollection SC,int newCapacity);

// Calls the given function for all strings. "Arg" is a used supplied argument
// that can be NULL that is passed to the function to call
void (*Apply)(StringCollection SC,int (*Applyfn)(char *,void * arg),void *arg);

// Calls the given function for each string and saves all results
// in an integer vector
int *(*Map)(StringCollection SC,int (*Applyfn)(char *));

// Pushes a string, using the collection as a stack
int (*Push)(StringCollection SC,char *str);

// Pops the last string off the collection
char * (*Pop)(StringCollection SC);

// Replaces the character string at the given position with a new one
char *(*ReplaceAt)(StringCollection SC,int idx,char *newval);

// Returns whether the collection makes case sensitive comparisons or not
int (*IsCaseSensitive)(StringCollection SC);

// Sets case sensitivity by comparisons
int (*SetCaseSensitive)(StringCollection SC,int newval);

// Compares two string collections
bool (*Equal)(StringCollection SC1,StringCollection SC2);

// Copy a string collection
StringCollection (*Copy)(StringCollection SC);
} StringCollectionInterface;
/*
Note that this lengthy structure is not replicated at each string collection
object. Each string collection holds just a pointer to it, spending only
sizeof(void *) bytes.
*/


// Definition of the String Collection type
struct _StringCollection {
StringCollectionInterface *lpVtbl; // The table of functions
int count; /* in element size units */
char **contents; /* The contents of the collection */
int capacity; /* in element_size units */
unsigned int flags; // Read-only or other flags
};

struct _StringEnumerator;
typedef struct _StringEnumeratorFunctions {
int (*Next)(struct _StringEnumerator *);
int (*Previous)(struct _StringEnumerator *);
char *(*GetCurrent)(struct _StringEnumerator *);
int (*SetCurrent)(struct _StringEnumerator *,int);
} StringEnumeratorFunctions;

typedef struct _StringEnumerator {
StringEnumeratorFunctions *lpVtbl;
StringCollection SC;
int CurrentIndex;
} StringEnumerator;

// This are the only exported functions from this module
StringCollection newStringCollection(int startsize);
#if 0
char *operator[](StringCollection *,int);
char *operator[]=(StringCollection SC,int idx,char *newval);
#endif
/* ------------------------------------------------------------------------
* LIST Interface *
* This describes the single linked list data structure functions *
* Each list objects has a list composed of list elemants. *
*-------------------------------------------------------------------------*/
typedef struct _list_element {
struct _list_element *Next;
char Data[];
} list_element;

typedef struct _List List;
typedef struct {
// Returns the number of elements stored
int (*GetCount)(List AL);

// Is this collection read only?
int (*IsReadOnly)(List AL);

// Sets this collection read-only or unsets the read-only flag
int (*SetReadOnly)(List AL,int flag);

// Adds one element at the end. Given element is copied
int (*Add)(List AL,void *newval);

// Clears all data and frees the memory
int (*Clear)(List AL);

//Case sensitive search of a character string in the data
bool (*Contains)(List AL,void *str);

// Copies all strings into a NULL terminated vector
List (*Copy)(List AL);

//Returns the index of the given string or -1 if not found
int (*IndexOf)(List AL,void *SearchedElement);

// Inserts a value at the position zero.
int (*Insert)(List AL,void *);

// Inserts a value at the given position
int (*InsertAt)(List AL,int idx,void *newval);

// Returns the list at the given position
void *(*IndexAt)(List AL,int idx);

// Removes the given string if found
int (*Remove)(List AL,void *);

//Removes the string at the indicated position
int (*RemoveAt)(List AL,int idx);

// Frees the memory used by the collection
int (*Finalize)(List AL);

// Pushes a string, using the collection as a stack
int (*Push)(List AL,void *str);

// Pops the last string off the list
list_element * (*Pop)(List AL);

// Replaces the character string at the given position with a new one
void *(*ReplaceAt)(List AL,int idx,void *newval);

// Sorts the list
List (*Sort)(List l,int (*compar)(const void *,const void *));

// Reverses the list
List (*Reverse)(List l);

// Gets an element range from the list
List (*GetRange)(List l,int start,int end);

// Compares two list (Shallow comparison)
bool (*Equal)(List l1,List l2);

// Add a list at the end of another
List (*Append)(List l1,List l2);

// Comparison function
int (*CompareFn)(void * elem1, void *elem2);

// Set The comparison function
CompareFunction (*SetCompareFunction)(List l,CompareFunction fn);
} ListInterface;

struct _List {
ListInterface *lpVtbl;
size_t ElementSize;
int count; /* in elements units */
list_element *Last; /* The last item */
list_element *First; /* The contents of the list start here */
unsigned Flags;
};
List newList(int element_size);
#if 0
list_element * operator[]=(List &l,size_t position,void *data);
list_element * operator[](List &l,int position);
#endif
/*-------------------------------------------------------------------------
* inline functions
*------------------------------------------------------------------------*/
#ifdef _MSC
#define inline static
#endif
inline list_element * GetFirst(List *l)
{
return l->First;
}
inline list_element * GetNext(list_element *l)
{
return l->Next;
}

inline list_element * GetLast(List *l)
{
return l->Last;
}

/*****************************************************************************
* *
* The array list *
* We have now a general framework for handling string collections. Looking
* at the code, it is easy to see that with a little effort, we could make
* this much more general if we would replace the strings with a fixed size
* object, that can be any data structure. This general container is present
* in other languages like C#, where it is called ArrayList. You can store
* in an ArrayList anything, in C# it is not even required that the objects
* stored inside should be of the same type.

* Since the nature of the objects stored is not known to the container,
* it is necessary to cast the result of an ArrayList into the final type
* that the user knows it is in there. In C# this is the object, the root
* of the object hierarchy, in C it is the void pointer, a pointer that can
* point to any kind of object.

* If we look at the code of one of the string collection functions we can
* see the following:
* static char *IndexAt(struct _StringCollection *SC,int idx)
* {
* if (idx >=SC.count || idx < 0)
* return NULL;
* return SC.contents[idx];
* }

* We can easily generalize this to a container by changing the char pointer
* result declaration to just a void pointer.

****************************************************************************/

// Forward declaration of the string collection type
typedef struct _ArrayList ArrayList;

// Definition of the functions associated with this type.
typedef struct {
// Returns the number of elements stored
int (*GetCount)(ArrayList *AL);

// Is this collection read only?
int (*IsReadOnly)(ArrayList *AL);

// Sets this collection read-only or unsets the read-only flag
int (*SetReadOnly)(ArrayList *AL,int flag);

// Adds one element at the end. Given element is copied
int (*Add)(ArrayList *AL,void *newval);

// Adds a NULL terminated table of strings
int (*AddRange)(ArrayList *AL,void **newvalues);

// Clears all data and frees the memory
int (*Clear)(ArrayList *AL);

//Case sensitive search of a character string in the data
bool (*Contains)(ArrayList *AL,void *str);

// Copies all strings into a NULL terminated vector
void **(*CopyTo)(ArrayList *AL);

//Returns the index of the given string or -1 if not found
int (*IndexOf)(ArrayList *AL,void *SearchedString);

// Inserts a string at the position zero.
int (*Insert)(ArrayList *AL,void *);

// Inserts a string at the given position
int (*InsertAt)(ArrayList *AL,int idx,void *newval);

// Returns the string at the given position
void *(*IndexAt)(ArrayList *AL,int idx);

// Removes the given string if found
int (*Remove)(ArrayList *AL,void *);

//Removes the string at the indicated position
int (*RemoveAt)(ArrayList *AL,int idx);

// Frees the memory used by the collection
int (*Finalize)(ArrayList *AL);

// Returns the current capacity of the collection
int (*GetCapacity)(ArrayList *AL);

// Sets the capacity if there are no items in the collection
bool (*SetCapacity)(ArrayList *AL,int newCapacity);

// Calls the given function for all strings. "Arg" is a used supplied argument
// that can be NULL that is passed to the function to call
void (*Apply)(ArrayList *AL,int (*Applyfn)(void *,void * arg),void *arg);

// Pushes a string, using the collection as a stack
int (*Push)(ArrayList *AL,void *str);

// Pops the last string off the collection
void * (*Pop)(ArrayList *AL);

// Replaces the character string at the given position with a new one
void *(*ReplaceAt)(ArrayList *AL,int idx,void *newval);

} ArrayListInterface;

// Definition of the String Collection type
struct _ArrayList {
ArrayListInterface *lpVtbl; // The table of functions
int count; /* number of elements in the array */
void **contents; /* The contents of the collection */
int capacity; /* allocated space in the contents vector */
unsigned int flags; // Read-only or other flags
size_t ElementSize; // Size of the elements stored in this array.
};

// This are the only exported functions from this module
ArrayList newArrayList(size_t elementsize,int startsize);
#if 0
void *operator[](ArrayList AL,int idx);
void *operator[]=(ArrayList AL,int idx,void *newval);
#endif
//******************************************************************************
//
// ErrorHandling
//
//******************************************************************************
#define CONTAINER_ERROR_BADARG (0x80070057)
#define CONTAINER_ERROR_NOMEMORY (0x8007000E)
#define CONTAINER_ERROR_INDEX -3
#define CONTAINER_ERROR_READONLY -4
#define CONTAINER_ERROR_FILEOPEN -5
void ContainerRaiseError(char *fnname,unsigned errorcode);
#endif
 
B

Ben Bacarisse

jacob navia said:
Sorry, I have mixed up things when transferring to the
email sofwtare. Here is an updated version, compatible with gcc

Apart from a number of spacing changes the only difference i can see
(that applies to non-MSC implementations) is:

6c6,11
#ifndef __LCC__
#define NO_GC
#define bool int
#define true 1
#define false 0
#endif

Why replace a standard header with something code that breaks any
program that wants to use stdbool?

The use of NO_GC suggests that it is optional, but I can't see where
anything gets freed. The choice seems to be between GC and a space
leak.

Can you post a main function that uses your list code because I still
can't see how it could do anything at all (Lists, rather than List *s,
seem to be passed to all the functions)?

<snip>
 
B

Barry Schwarz

This is the first part of this posting. This is the header file
containers.h
--------------------------------------------------------cut here

#ifndef __containers_h__
#define __containers_h__
snip

typedef struct _StringCollection StringCollection;
struct _StringEnumerator;

Is there some reason you chose to invade the implementation name
space?
 
B

Barry Schwarz

He is an *implementor*, proposing a new *implementation* feature. He
is therefore quite within his rights to use the implementation
namespace. Of course, he runs the risk of clashing with other
implementations, but I don't see a way around that.

Everyone who writes code is an implementer.

There is no indication this was proposed to become a standard header
and part of the standard run-time library or built into the
compiler/linker. Paragraph 7.1.3 reserves these names for use in that
context.
 
B

bartc

Barry Schwarz said:
Everyone who writes code is an implementer.

But not necessarily of a C language system. He can add extensions to his C
implementation which I can guess can use the underscore prefix.

However this library doesn't seem specific to one implementation so perhaps
the underscores are not appropriate. As I think you point out next:
 
J

James Kuyper

Barry said:
Everyone who writes code is an implementer.

RH was referring to an implementor of a C implementation. I been writing
C code for more than 3 decades, and I've implemented a great many
things, but I've never implemented C itself, not even a simplified
version thereof. Jacob has. When acting in his role as a C implementor,
he is allowed to use the name space reserved for implementors of C.
 
T

Tech07

jacob said:
This is the first part of this posting. This is the header file
containers.h
--------------------------------------------------------cut here

#ifndef __containers_h__
#define __containers_h__
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
/*
A string collection is a table of zero terminated strings that will
grow automatically when you add elements to it.

How old are you?
As all other containers in this proposal,

Whoa! Cowboy, do really believe that people are gonna read anything further
unless they too believe that a string is a container? Prove it cowboy!
"string"? You mean like roping calves? That would be a rope. "string", like
that 80-year old lady in Europe uses to painstakingly make <I don't think
we'll ever know what she makes>, or is that "thread"? Is there sheep
involved in that process? Maybe she just gets the raw materials in a
container, I dunno. Do you?

(Are you howling at the moon?).
 
C

Chris M. Thomasson

Tech07 said:
How old are you?


Whoa! Cowboy, do really believe that people are gonna read anything
further unless they too believe that a string is a container?

IMVHO, a string is a container of characters.



Prove it cowboy!

Yeeeeeeeeeeeeee, Hawwwwwwwwwww!

;^D



"string"? You mean like roping calves? That would be a rope.

Explain to me how to implement a rope... Please?



"string", like that 80-year old lady in Europe uses to painstakingly make
<I don't think we'll ever know what she makes>, or is that "thread"? Is
there sheep involved in that process? Maybe she just gets the raw
materials in a container, I dunno. Do you?

(Are you howling at the moon?).

;^|
 
C

Chris M. Thomasson

Chris M. Thomasson said:
IMVHO, a string is a container of characters.

Correction...

a string is a container of characters, with the last character being equal
to '\0'.


[...]
 
T

Tech07

Chris said:
Correction...

a string is a container of characters, with the last character being
equal to '\0'.
I have more important things to do than to consult to you for free. :p
 
T

Tech07

jacob said:
This is the first part of this posting. This is the header file
containers.h
--------------------------------------------------------cut here

#ifndef __containers_h__
#define __containers_h__
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
/*
A string collection is a table of zero terminated strings that will
grow automatically when you add elements to it.

That would be a student look at it (an elementary student of the science).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,054
Latest member
LucyCarper

Latest Threads

Top