I just want to share some code with you, and have some comments and
improvements if you want.
This header file allocates and add and delete items of any kind of data
from a very fast array:
#include <stdlib.h>
#ifndef __LIST_H__
#define __LIST_H__
#define NEW(type) (type*)malloc(sizeof(type))
#define DEFAULT_SIZE 12
#define lNEW(type) ({ \
int *list = (int*)malloc( (sizeof(type)*DEFAULT_SIZE) \
+ (sizeof(int)*3)); \
*list++=sizeof(type); \
*list++=DEFAULT_SIZE; \
*list++=0; \
(type*)list; })
#define lSIZE(list) (*((int*)list-1))
#define lALLOCATED(list) (*((int*)list-2))
#define lOBJECTSIZE(list) (*((int*)list-3))
#define lNEWITEM(list) ({ \
if (lSIZE(list)>=lALLOCATED(list)) { \
list = (void*) ((int*)realloc((int*)list-3, \
(lSIZE(list) + DEFAULT_SIZE) * \
lOBJECTSIZE(list) + \
sizeof(int)*3) \
+ 3); \
lALLOCATED(list)+=DEFAULT_SIZE; \
} \
&list[lSIZE(list)++]; \
})
#define lAPPEND(list,obj) *lNEWITEM(list)=obj;
#define lDELITEM(list,obj) *obj=list[--lSIZE(list)]
#define lFREE(list) free((int*)list-3)
#endif
It is a strange policy, you add/remove elements only at the end, but you
allow random access? A mix between a stack and an array? (but definitely
not a list).
In my system, it is able to add more than 1.000.000 of items per
second, so I think it is quite fast.
This is not quite fast. >100.000.000 is quite fast (on a Pentium-M
1.6Ghz). The best is to compare it the speed of the C array ;-)
And the interesting thing is that you can use the resulting array as a
normal C array, using [] to access all of its data.
According to my experience, I think it is a good idea to have C-like
access for low-level very fast arrays, but it is not a good idea to mix
it with append/remove-like functions. For low-level, C-like array random
access, checked get/set and resize are a better choice. Function like
cat/append/remove start to be high level functions where the user should
not be concerned by the fact that the array pointer may change after a
cat/append, that is the array should stay the same even when its
capacity increases.
Example:
typedef struct {
int onething;
char *another;
} Object;
Object *obj = lNEW(Object);
Object o = {12, "haha"};
Object *oo = lNEWITEM(obj);
lAPPEND(obj, o);
oo->another="hehe";
printf ("%i, %s", lSIZE(obj), obj[1].another);
=> prints "2, hehe"
I'm using GCC. If anyone wants to check out it using other compilers, I
will thank.
Here is below the header of a low-level fast array interface
(implementation is an easy exercise ;-) ) which is part of my OOC
framework (required to compile, but easy to make it independent). It
allows C random access to data, it is type safe and do not use macros
(except for prefixing and some shortcuts, the later can be remove). Your
example becomes (adapted to array, not stack):
Object *obj = obj_array_new(2);
obj[0] = (Object*){12, "haha"};
obj[1] = obj[0];
obj[1].another = "hehe";
printf("%i, %s", sizeof *obj, obj[1].another);
it is easy to make a generic stack on top of this array implementation.
a+, ld.
-----------------
/* template file, multiple inclusion allowed */
/*
******************************
* Raw Array interface
* -----
* Object Oriented C programming
*
* Author: Laurent Deniau, (e-mail address removed)
*
* $Id: array_t.h,v 1.1 2004/07/04 13:52:09 ldeniau Exp $
*
* For more information, please see:
*
http://cern.ch/Laurent.Deniau/html/ooc/ooc.html
*
******************************
*/
/* NOTE-USER: raw array interface
array_T : element type (e.g. int)
array_T*: array type (e.g. int*)
array_T* PREFIX_array_new (size_t cnt );
array_T* PREFIX_array_alloc (size_t cnt );
array_T* PREFIX_array_cpy (array_T *a1 , const array_T *a2);
array_T* PREFIX_array_rawcpy (array_T *a1 , const array_T *src,
size_t cnt);
array_T* PREFIX_array_dup (const array_T *a );
array_T* PREFIX_array_rawdup (const array_T *src, size_t cnt);
array_T* PREFIX_array_resize (array_T *a , size_t cnt);
array_T* PREFIX_array_realloc(array_T *a , size_t cnt);
void PREFIX_array_del (array_T *a );
void PREFIX_array_free (array_T *a );
size_t PREFIX_array_cnt (const array_T *a );
array_T PREFIX_array_get (const array_T *a, size_t idx);
void PREFIX_array_set (array_T *a, size_t idx, array_T val);
*/
#ifndef array_T
#error "libooc: missing array_T definition"
#endif
#ifndef array_PREFIX
#define array_PREFIX array_T
#endif
/*
* ----------
* Externals
* ----------
*/
void* ooc_array_new_ ( size_t cnt , size_t esize,
size_t hsize, bool ex);
void* ooc_array_resize_(void* self, size_t cnt , size_t esize,
size_t hsize, bool ex);
void* ooc_array_cpy_ (void* dst , const void* src, size_t esize,
size_t hsize);
void* ooc_array_rawcpy_(void* dst , const void* src, size_t esize,
size_t hsize, size_t cnt);
void* ooc_array_dup_ ( const void* src, size_t esize,
size_t hsize);
void* ooc_array_rawdup_( const void* src, size_t esize,
size_t hsize, size_t cnt);
void ooc_array_badrng_(const char *file, int line);
/*
* ---------------------------------------
* Array interface/inlined implementation
* ---------------------------------------
*/
#ifndef OOC_TYPE_ARRAY_C
#define T OOC_CAT(array_PREFIX, _array)
#define F(f) OOC_CAT3(T,_,f)
#define B(p) ((struct T*)((char*)(p) - offsetof(struct T, data)))
struct T {
const size_t cnt; /* read-only field */
#if OOC_ISO_C < OOC_ISO_C99
array_T data[1]; /* public field, undefined behavior, but... */
#else
array_T data[]; /* public field, defined behavior */
#endif
};
static inline array_T*
F(new) (size_t cnt)
{
return
ooc_array_new_(cnt, sizeof(array_T), offsetof(struct T, data), true);
}
static inline array_T*
F(alloc) (size_t cnt)
{
return
ooc_array_new_(cnt, sizeof(array_T), offsetof(struct T, data), false);
}
static inline array_T*
F(cpy) (array_T *dst, const array_T *src)
{
return ooc_array_cpy_((void*)dst, (void*)src,
sizeof(array_T), offsetof(struct T, data));
}
static inline array_T*
F(rawcpy) (array_T *dst, const array_T *src, size_t cnt)
{
return ooc_array_rawcpy_((void*)dst, (void*)src,
sizeof(array_T), offsetof(struct T, data), cnt);
}
static inline array_T*
F(dup) (const array_T *src)
{
return ooc_array_dup_((void*)src, sizeof(array_T),
offsetof(struct T, data));
}
static inline array_T*
F(rawdup) (const array_T *src, size_t cnt)
{
return ooc_array_rawdup_((void*)src, sizeof(array_T),
offsetof(struct T, data), cnt);
}
static inline array_T*
F(resize) (array_T *self, size_t cnt)
{
return ooc_array_resize_((void*)self, cnt,
sizeof(array_T), offsetof(struct T, data), true);
}
static inline array_T*
F(realloc) (array_T *self, size_t cnt)
{
return ooc_array_resize_((void*)self, cnt,
sizeof(array_T), offsetof(struct T, data), false);
}
static inline void
F(del) (array_T *self)
{
if (self)
(ooc_free)(B(self));
}
static inline void
F(free) (array_T *self)
{
F(del)(self);
}
static inline size_t
F(cnt) (const array_T *self)
{
return B(self)->cnt;
}
static inline array_T
F(get) (const array_T *self, size_t idx)
{
if (idx >= B(self)->cnt)
ooc_array_badrng_(__FILE__, __LINE__);
return self[idx];
}
static inline void
F(set) (array_T *self, size_t idx, array_T val)
{
if (idx >= B(self)->cnt)
ooc_array_badrng_(__FILE__, __LINE__);
self[idx] = val;
}
#undef T
#undef F
#undef B
#endif /* OOC_TYPE_ARRAY_C */
#undef array_PREFIX
#undef array_T