J
jacob navia
This implements the ararylist container arraylist.c
----------------------------------------------------
#include "containers.h"
static int GetCount( ArrayList *AL);
static int IsReadOnly( ArrayList *AL);
static int SetReadOnly( ArrayList *AL,int newval);
static int Add( ArrayList *AL,void *newval);
static int AddRange( ArrayList *AL,void **newvalues);
static int Clear( ArrayList *AL);
static bool Contains( ArrayList *AL,void *str);
static void **CopyTo( ArrayList *AL);
static int IndexOf( ArrayList *AL,void *SearchedElement);
static int Insert( ArrayList *AL,void *);
static int InsertAt( ArrayList *AL,int idx,void *newval);
static void *IndexAt( ArrayList *AL,int idx);
static int Remove( ArrayList *AL,void *);
static int RemoveAt( ArrayList *AL,int idx);
static int Finalize( ArrayList *AL);
static int GetCapacity( ArrayList *AL);
static bool SetCapacity( ArrayList *AL,int newCapacity);
static void Apply(ArrayList *AL,int(*Applyfn)(void *,void *),void *arg);
static int Push(ArrayList *AL,void *str);
static void *Pop(ArrayList *AL);
static void *ReplaceAt(ArrayList *AL,int idx,void *newval);
static int IsCaseSensitive(ArrayList *AL);
static int SetCaseSensitive(ArrayList *AL,int newval);
static ArrayListInterface lpVtableAL = {
GetCount, IsReadOnly, SetReadOnly, Add, AddRange, Clear, Contains,
CopyTo, IndexOf, Insert, InsertAt, IndexAt, Remove, RemoveAt,
Finalize, GetCapacity, SetCapacity, Apply, Push, Pop, ReplaceAt,
};
#ifndef NO_GC
#include <gc.h>
#define MALLOC GC_malloc
#define FREE(a)
#else
#include <stdlib.h>
#define MALLOC malloc
#define FREE free
#endif
#ifndef DEFAULT_START_SIZE
#define DEFAULT_START_SIZE 20
#endif
static void *DuplicateElement(void *str,int size)
{
if (str == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
return NULL;
}
void *result = MALLOC(size);
if (result == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_NOMEMORY);
return NULL;
}
else memcpy(result,str,size);
return result;
}
#define AL_READONLY 1
#define AL_IGNORECASE 2
#define CHUNKSIZE 20
ArrayList newArrayList(size_t elementsize,int startsize)
{
ArrayList result;
if ((elementsize &0x800000) || elementsize == 0)
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
memset(&result,0,sizeof(result));
result.count = 0;
if (startsize <= 0)
startsize = DEFAULT_START_SIZE;
result.contents = MALLOC(startsize*elementsize);
if (result.contents == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_NOMEMORY);
}
else {
memset(result.contents,0,elementsize*startsize);
result.capacity = startsize;
result.lpVtbl = &lpVtableAL;
result.ElementSize = elementsize;
}
return result;
}
static int GetCount(ArrayList *AL)
{
return AL->count;
}
static int IsReadOnly(struct _ArrayList *AL)
{
return AL->flags & AL_READONLY ? 1 : 0;
}
static int SetReadOnly(struct _ArrayList *AL,int newval)
{
int oldval = AL->flags & AL_READONLY ? 1 : 0;
if (newval)
AL->flags |= AL_READONLY;
else
AL->flags &= ~AL_READONLY;
return oldval;
}
static int Resize(ArrayList *AL)
{
int newcapacity = AL->capacity + CHUNKSIZE;
void **oldcontents = AL->contents;
AL->contents = MALLOC(newcapacity*sizeof(void *));
if (AL->contents == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_NOMEMORY);
AL->contents = oldcontents;
return 0;
}
memset(AL->contents,0,sizeof(void *)*newcapacity);
memcpy(AL->contents,oldcontents,AL->count*sizeof(void *));
AL->capacity = newcapacity;
FREE(oldcontents);
return 1;
}
static int Add(ArrayList *AL,void *newval)
{
if (AL->flags & AL_READONLY)
return -1;
if (newval == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
return -2;
}
if (AL->count >= AL->capacity) {
if (!Resize(AL))
return 0;
}
AL->contents[AL->count] = DuplicateElement(newval,AL->ElementSize);
if (AL->contents[AL->count] == NULL) {
return 0;
}
AL->count++;
return AL->count;
}
static int AddRange(struct _ArrayList * AL,void **data)
{
int i = 0,c;
if (AL->flags & AL_READONLY)
return 0;
if (data == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
return -2;
}
c = AL->count;
while (data != NULL) {
int r = Add(AL,data);
if (r <= 0) {
while (AL->count > c) {
Pop(AL);
}
return r;
}
i++;
}
return AL->count;
}
static int Clear(struct _ArrayList *AL)
{
int oldval = AL->count;
if (AL->flags & AL_READONLY)
return 0;
for (int i=0; i<AL->count;i++) {
FREE(AL->contents);
AL->contents = NULL;
}
AL->count = 0;
return oldval;
}
static bool Contains(ArrayList *AL,void *str)
{
if (str == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
return false;
}
for (int i = 0; i<AL->count;i++) {
if (!memcmp(AL->contents,str,AL->ElementSize))
return true;
}
return false;
}
static void **CopyTo(ArrayList *AL)
{
void **result = MALLOC(AL->count*sizeof(void *));
int i;
if (result == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_NOMEMORY);
return NULL;
}
for (i=0; i<AL->count;i++) {
result = DuplicateElement(AL->contents,AL->ElementSize);
if (result == NULL) {
return NULL;
}
}
result = NULL;
return result;
}
static int IndexOf(ArrayList *AL,void *str)
{
int i;
if (str == NULL)
return -1;
for (i=0; i<AL->count;i++) {
if (!memcmp(AL->contents,str,AL->ElementSize)) {
return i;
}
}
return -1;
}
static void *IndexAt(ArrayList *AL,int idx)
{
if (idx >=AL->count || idx < 0) {
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
return NULL;
}
return AL->contents[idx];
}
#if 0
// Under lcc-win you can use the more natural [ ] syntax.
void *operator[](ArrayList *AL,int idx)
{
return IndexAt(AL,idx);
}
#endif
static int InsertAt(ArrayList *AL,int idx,void *newval)
{
if (AL->flags & AL_READONLY)
return 0;
if (idx < 0 || idx > AL->count) {
ContainerRaiseError(__func__,CONTAINER_ERROR_INDEX);
return -1;
}
if (AL->count >= (AL->capacity-1)) {
if (!Resize(AL))
return 0;
}
if (idx == 0) {
if (AL->count > 0)
memmove(AL->contents+1,AL->contents,AL->count*sizeof(void *));
AL->contents[0] = newval;
}
else if (idx == AL->count) {
AL->contents[idx] = newval;
}
else if (idx < AL->count) {
memmove(AL->contents+idx+1,AL->contents+idx,(AL->count-idx+1)*sizeof(void *));
AL->contents[idx] = newval;
}
AL->count++;
return AL->count;
}
static int Insert(ArrayList *AL,void *newval)
{
if (AL->flags & AL_READONLY)
return 0;
return InsertAt(AL,0,newval);
}
static int RemoveAt(ArrayList *AL,int idx)
{
if (idx >= AL->count || idx < 0 || (AL->flags & AL_READONLY))
return -1;
if (AL->count == 0)
return -2;
FREE(AL->contents[idx]);
if (idx < (AL->count-1)) {
memmove(AL->contents+idx,AL->contents+idx+1,
(AL->count-idx)*sizeof(void *));
}
AL->contents[AL->count-1]=NULL;
AL->count--;
return AL->count;
}
static int Remove(ArrayList *AL,void *str)
{
int idx = IndexOf(AL,str);
if (idx < 0)
return idx;
return RemoveAt(AL,idx);
}
static int Push(ArrayList *AL,void *str)
{
void *r;
if (AL->flags&AL_READONLY)
return 0;
if (AL->count >= AL->capacity-1) {
if (!Resize(AL))
return 0;
}
r = DuplicateElement(str,AL->ElementSize);
if (r == NULL)
return 0;
AL->contents[AL->count++] = r;
return AL->count;
}
static void * Pop(ArrayList *AL)
{
void *result;
if ((AL->flags&AL_READONLY) || AL->count == 0)
return NULL;
AL->count--;
result = AL->contents[AL->count];
AL->contents[AL->count] = NULL;
return result;
}
static int Finalize(ArrayList *AL)
{
int result = AL->count;
for (int i=0; i<AL->count;i++) {
FREE(AL->contents);
}
FREE(AL->contents);
FREE(&AL);
return result;
}
static int GetCapacity(ArrayList *AL)
{
return AL->capacity;
}
static bool SetCapacity(struct _ArrayList *AL,int newCapacity)
{
if (AL->count != 0)
return false;
FREE(AL->contents);
AL->contents = MALLOC(newCapacity*sizeof(void *));
if (AL->contents == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_NOMEMORY);
return false;
}
memset(AL->contents,0,sizeof(void *)*newCapacity);
AL->capacity = newCapacity;
return 1;
}
static void Apply(struct _ArrayList *AL,int (*Applyfn)(void *,void *),void *arg)
{
for (int i=0; i<AL->count;i++) {
Applyfn(AL->contents,arg);
}
}
#if 0
// Under lcc-win you can use the more natural [ ] syntax
void * __declspec(naked) operator[]=(ArrayList *AL,int idx,void *newval)
{
}
#endif
static int ReplaceAt(ArrayList *AL,int idx,void *newval)
{
if (AL->flags & AL_READONLY)
return 0;
if (idx < 0 || idx > AL->count)
return 0;
FREE(AL->contents[idx]);
AL->contents[idx] = newval;
return 1;
}
#if 0
void *operator[]=(ArrayList AL,int idx,void *newval)
{
return ReplaceAt(AL,idx,newval);
}
#endif
#ifdef TEST
#include <stdio.h>
static void PrintArrayList(ArrayList *AL)
{
printf("Count %d, Capacity %d\n",AL->count,AL->capacity);
for (int i=0; i<AL->count;i++) {
printf("%s\n",AL);
}
printf("\n");
}
int main(void)
{
ArrayList AL = newArrayList();
char *p;
AL.lpVtbl->Add(&AL,"Martin");
AL.lpVtbl->Insert(&AL,"Jakob");
if (!AL.lpVtbl->Contains(&AL,"Martin")) {
printf("error, string not found!\n");
}
printf("Count should be 2, is %d\n",AL->GetCount());
PrintArrayList(&AL);
AL.lpVtbl->InsertAt(1,"Position 1");
AL.lpVtbl->InsertAt(2,"Position 2");
PrintArrayList(AL);
AL.lpVtbl->Remove("Jakob");
PrintArrayList(AL);
AL.lpVtbl->Push("pushed");
PrintArrayList(&AL);
AL.lpVtbl->Pop();
PrintArrayList(AL);
p = AL[1];
printf("Item position 1:%s\n",p);
PrintArrayList(&AL);
}
#endif
----------------------------------------------------
#include "containers.h"
static int GetCount( ArrayList *AL);
static int IsReadOnly( ArrayList *AL);
static int SetReadOnly( ArrayList *AL,int newval);
static int Add( ArrayList *AL,void *newval);
static int AddRange( ArrayList *AL,void **newvalues);
static int Clear( ArrayList *AL);
static bool Contains( ArrayList *AL,void *str);
static void **CopyTo( ArrayList *AL);
static int IndexOf( ArrayList *AL,void *SearchedElement);
static int Insert( ArrayList *AL,void *);
static int InsertAt( ArrayList *AL,int idx,void *newval);
static void *IndexAt( ArrayList *AL,int idx);
static int Remove( ArrayList *AL,void *);
static int RemoveAt( ArrayList *AL,int idx);
static int Finalize( ArrayList *AL);
static int GetCapacity( ArrayList *AL);
static bool SetCapacity( ArrayList *AL,int newCapacity);
static void Apply(ArrayList *AL,int(*Applyfn)(void *,void *),void *arg);
static int Push(ArrayList *AL,void *str);
static void *Pop(ArrayList *AL);
static void *ReplaceAt(ArrayList *AL,int idx,void *newval);
static int IsCaseSensitive(ArrayList *AL);
static int SetCaseSensitive(ArrayList *AL,int newval);
static ArrayListInterface lpVtableAL = {
GetCount, IsReadOnly, SetReadOnly, Add, AddRange, Clear, Contains,
CopyTo, IndexOf, Insert, InsertAt, IndexAt, Remove, RemoveAt,
Finalize, GetCapacity, SetCapacity, Apply, Push, Pop, ReplaceAt,
};
#ifndef NO_GC
#include <gc.h>
#define MALLOC GC_malloc
#define FREE(a)
#else
#include <stdlib.h>
#define MALLOC malloc
#define FREE free
#endif
#ifndef DEFAULT_START_SIZE
#define DEFAULT_START_SIZE 20
#endif
static void *DuplicateElement(void *str,int size)
{
if (str == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
return NULL;
}
void *result = MALLOC(size);
if (result == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_NOMEMORY);
return NULL;
}
else memcpy(result,str,size);
return result;
}
#define AL_READONLY 1
#define AL_IGNORECASE 2
#define CHUNKSIZE 20
ArrayList newArrayList(size_t elementsize,int startsize)
{
ArrayList result;
if ((elementsize &0x800000) || elementsize == 0)
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
memset(&result,0,sizeof(result));
result.count = 0;
if (startsize <= 0)
startsize = DEFAULT_START_SIZE;
result.contents = MALLOC(startsize*elementsize);
if (result.contents == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_NOMEMORY);
}
else {
memset(result.contents,0,elementsize*startsize);
result.capacity = startsize;
result.lpVtbl = &lpVtableAL;
result.ElementSize = elementsize;
}
return result;
}
static int GetCount(ArrayList *AL)
{
return AL->count;
}
static int IsReadOnly(struct _ArrayList *AL)
{
return AL->flags & AL_READONLY ? 1 : 0;
}
static int SetReadOnly(struct _ArrayList *AL,int newval)
{
int oldval = AL->flags & AL_READONLY ? 1 : 0;
if (newval)
AL->flags |= AL_READONLY;
else
AL->flags &= ~AL_READONLY;
return oldval;
}
static int Resize(ArrayList *AL)
{
int newcapacity = AL->capacity + CHUNKSIZE;
void **oldcontents = AL->contents;
AL->contents = MALLOC(newcapacity*sizeof(void *));
if (AL->contents == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_NOMEMORY);
AL->contents = oldcontents;
return 0;
}
memset(AL->contents,0,sizeof(void *)*newcapacity);
memcpy(AL->contents,oldcontents,AL->count*sizeof(void *));
AL->capacity = newcapacity;
FREE(oldcontents);
return 1;
}
static int Add(ArrayList *AL,void *newval)
{
if (AL->flags & AL_READONLY)
return -1;
if (newval == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
return -2;
}
if (AL->count >= AL->capacity) {
if (!Resize(AL))
return 0;
}
AL->contents[AL->count] = DuplicateElement(newval,AL->ElementSize);
if (AL->contents[AL->count] == NULL) {
return 0;
}
AL->count++;
return AL->count;
}
static int AddRange(struct _ArrayList * AL,void **data)
{
int i = 0,c;
if (AL->flags & AL_READONLY)
return 0;
if (data == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
return -2;
}
c = AL->count;
while (data != NULL) {
int r = Add(AL,data);
if (r <= 0) {
while (AL->count > c) {
Pop(AL);
}
return r;
}
i++;
}
return AL->count;
}
static int Clear(struct _ArrayList *AL)
{
int oldval = AL->count;
if (AL->flags & AL_READONLY)
return 0;
for (int i=0; i<AL->count;i++) {
FREE(AL->contents);
AL->contents = NULL;
}
AL->count = 0;
return oldval;
}
static bool Contains(ArrayList *AL,void *str)
{
if (str == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
return false;
}
for (int i = 0; i<AL->count;i++) {
if (!memcmp(AL->contents,str,AL->ElementSize))
return true;
}
return false;
}
static void **CopyTo(ArrayList *AL)
{
void **result = MALLOC(AL->count*sizeof(void *));
int i;
if (result == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_NOMEMORY);
return NULL;
}
for (i=0; i<AL->count;i++) {
result = DuplicateElement(AL->contents,AL->ElementSize);
if (result == NULL) {
return NULL;
}
}
result = NULL;
return result;
}
static int IndexOf(ArrayList *AL,void *str)
{
int i;
if (str == NULL)
return -1;
for (i=0; i<AL->count;i++) {
if (!memcmp(AL->contents,str,AL->ElementSize)) {
return i;
}
}
return -1;
}
static void *IndexAt(ArrayList *AL,int idx)
{
if (idx >=AL->count || idx < 0) {
ContainerRaiseError(__func__,CONTAINER_ERROR_BADARG);
return NULL;
}
return AL->contents[idx];
}
#if 0
// Under lcc-win you can use the more natural [ ] syntax.
void *operator[](ArrayList *AL,int idx)
{
return IndexAt(AL,idx);
}
#endif
static int InsertAt(ArrayList *AL,int idx,void *newval)
{
if (AL->flags & AL_READONLY)
return 0;
if (idx < 0 || idx > AL->count) {
ContainerRaiseError(__func__,CONTAINER_ERROR_INDEX);
return -1;
}
if (AL->count >= (AL->capacity-1)) {
if (!Resize(AL))
return 0;
}
if (idx == 0) {
if (AL->count > 0)
memmove(AL->contents+1,AL->contents,AL->count*sizeof(void *));
AL->contents[0] = newval;
}
else if (idx == AL->count) {
AL->contents[idx] = newval;
}
else if (idx < AL->count) {
memmove(AL->contents+idx+1,AL->contents+idx,(AL->count-idx+1)*sizeof(void *));
AL->contents[idx] = newval;
}
AL->count++;
return AL->count;
}
static int Insert(ArrayList *AL,void *newval)
{
if (AL->flags & AL_READONLY)
return 0;
return InsertAt(AL,0,newval);
}
static int RemoveAt(ArrayList *AL,int idx)
{
if (idx >= AL->count || idx < 0 || (AL->flags & AL_READONLY))
return -1;
if (AL->count == 0)
return -2;
FREE(AL->contents[idx]);
if (idx < (AL->count-1)) {
memmove(AL->contents+idx,AL->contents+idx+1,
(AL->count-idx)*sizeof(void *));
}
AL->contents[AL->count-1]=NULL;
AL->count--;
return AL->count;
}
static int Remove(ArrayList *AL,void *str)
{
int idx = IndexOf(AL,str);
if (idx < 0)
return idx;
return RemoveAt(AL,idx);
}
static int Push(ArrayList *AL,void *str)
{
void *r;
if (AL->flags&AL_READONLY)
return 0;
if (AL->count >= AL->capacity-1) {
if (!Resize(AL))
return 0;
}
r = DuplicateElement(str,AL->ElementSize);
if (r == NULL)
return 0;
AL->contents[AL->count++] = r;
return AL->count;
}
static void * Pop(ArrayList *AL)
{
void *result;
if ((AL->flags&AL_READONLY) || AL->count == 0)
return NULL;
AL->count--;
result = AL->contents[AL->count];
AL->contents[AL->count] = NULL;
return result;
}
static int Finalize(ArrayList *AL)
{
int result = AL->count;
for (int i=0; i<AL->count;i++) {
FREE(AL->contents);
}
FREE(AL->contents);
FREE(&AL);
return result;
}
static int GetCapacity(ArrayList *AL)
{
return AL->capacity;
}
static bool SetCapacity(struct _ArrayList *AL,int newCapacity)
{
if (AL->count != 0)
return false;
FREE(AL->contents);
AL->contents = MALLOC(newCapacity*sizeof(void *));
if (AL->contents == NULL) {
ContainerRaiseError(__func__,CONTAINER_ERROR_NOMEMORY);
return false;
}
memset(AL->contents,0,sizeof(void *)*newCapacity);
AL->capacity = newCapacity;
return 1;
}
static void Apply(struct _ArrayList *AL,int (*Applyfn)(void *,void *),void *arg)
{
for (int i=0; i<AL->count;i++) {
Applyfn(AL->contents,arg);
}
}
#if 0
// Under lcc-win you can use the more natural [ ] syntax
void * __declspec(naked) operator[]=(ArrayList *AL,int idx,void *newval)
{
}
#endif
static int ReplaceAt(ArrayList *AL,int idx,void *newval)
{
if (AL->flags & AL_READONLY)
return 0;
if (idx < 0 || idx > AL->count)
return 0;
FREE(AL->contents[idx]);
AL->contents[idx] = newval;
return 1;
}
#if 0
void *operator[]=(ArrayList AL,int idx,void *newval)
{
return ReplaceAt(AL,idx,newval);
}
#endif
#ifdef TEST
#include <stdio.h>
static void PrintArrayList(ArrayList *AL)
{
printf("Count %d, Capacity %d\n",AL->count,AL->capacity);
for (int i=0; i<AL->count;i++) {
printf("%s\n",AL);
}
printf("\n");
}
int main(void)
{
ArrayList AL = newArrayList();
char *p;
AL.lpVtbl->Add(&AL,"Martin");
AL.lpVtbl->Insert(&AL,"Jakob");
if (!AL.lpVtbl->Contains(&AL,"Martin")) {
printf("error, string not found!\n");
}
printf("Count should be 2, is %d\n",AL->GetCount());
PrintArrayList(&AL);
AL.lpVtbl->InsertAt(1,"Position 1");
AL.lpVtbl->InsertAt(2,"Position 2");
PrintArrayList(AL);
AL.lpVtbl->Remove("Jakob");
PrintArrayList(AL);
AL.lpVtbl->Push("pushed");
PrintArrayList(&AL);
AL.lpVtbl->Pop();
PrintArrayList(AL);
p = AL[1];
printf("Item position 1:%s\n",p);
PrintArrayList(&AL);
}
#endif