srcs/toolbox/array.c

00001 /* 
00002  * Copyright (c) 2005-2012 by KoanLogic s.r.l. - All rights reserved.  
00003  */
00004 
00005 #include <stdint.h>
00006 #include <u/libu.h>
00007 #include <toolbox/array.h>
00008 
00009 /* for C89 implementations */
00010 #ifndef SIZE_MAX
00011 #define SIZE_MAX ((size_t) -1)
00012 #endif
00013 
00014 struct u_array_s
00015 {
00016     size_t nslots;
00017     u_array_type_t type;
00018     void *base;
00019 };
00020 
00021 #define U_ARRAY_TYPE_IS_VALID(t) \
00022     (t > U_ARRAY_TYPE_UNSET && t <= U_ARRAY_TYPE_MAX)
00023 
00024 static size_t sizeof_type[U_ARRAY_TYPE_MAX + 1] =
00025 {
00026     0,                              /* U_ARRAY_TYPE_UNSET  = 0          */
00027 #ifdef HAVE__BOOL
00028     sizeof(_Bool),                  /* U_ARRAY_TYPE_BOOL                */
00029 #endif  /* HAVE__BOOL */
00030     sizeof(char),                   /* U_ARRAY_TYPE_CHAR                */
00031     sizeof(unsigned char),          /* U_ARRAY_TYPE_U_CHAR              */
00032     sizeof(short),                  /* U_ARRAY_TYPE_SHORT               */
00033     sizeof(unsigned short),         /* U_ARRAY_TYPE_U_SHORT             */
00034     sizeof(int),                    /* U_ARRAY_TYPE_INT                 */
00035     sizeof(unsigned int),           /* U_ARRAY_TYPE_U_INT               */
00036     sizeof(long),                   /* U_ARRAY_TYPE_LONG                */
00037     sizeof(unsigned long),          /* U_ARRAY_TYPE_U_LONG              */
00038 #ifdef HAVE_LONG_LONG
00039     sizeof(long long),              /* U_ARRAY_TYPE_LONG_LONG           */
00040     sizeof(unsigned long long),     /* U_ARRAY_TYPE_U_LONG_LONG         */
00041 #endif  /* HAVE_LONG_LONG */
00042 #ifdef HAVE_INTMAX_T
00043     sizeof(intmax_t),               /* U_ARRAY_TYPE_INTMAX              */
00044     sizeof(uintmax_t),              /* U_ARRAY_TYPE_U_INTMAX            */
00045 #endif  /* HAVE_INTMAX_T */
00046     sizeof(float),                  /* U_ARRAY_TYPE_FLOAT               */
00047     sizeof(double),                 /* U_ARRAY_TYPE_DOUBLE              */
00048 #ifdef HAVE_LONG_DOUBLE
00049     sizeof(long double),            /* U_ARRAY_TYPE_LONG_DOUBLE         */
00050 #endif  /* HAVE_LONG_DOUBLE */
00051 #ifdef HAVE_FLOAT__COMPLEX
00052     sizeof(float _Complex),         /* U_ARRAY_TYPE_FLOAT_COMPLEX       */
00053 #endif  /* HAVE_FLOAT__COMPLEX */
00054 #ifdef HAVE_DOUBLE__COMPLEX
00055     sizeof(double _Complex),        /* U_ARRAY_TYPE_DOUBLE_COMPLEX      */
00056 #endif  /* HAVE_DOUBLE__COMPLEX */
00057 #ifdef HAVE_LONG_DOUBLE__COMPLEX
00058     sizeof(long double _Complex),   /* U_ARRAY_TYPE_LONG_DOUBLE_COMPLEX */
00059 #endif  /* HAVE_LONG_DOUBLE__COMPLEX */
00060     sizeof(void *)                  /* U_ARRAY_TYPE_PTR                 */
00061 };
00062 
00063 #define MAX_NSLOTS(da)  (SIZE_MAX / sizeof_type[da->type])
00064 
00135 int u_array_create (u_array_type_t t, size_t nslots, u_array_t **pda)
00136 {
00137     u_array_t *da = NULL;
00138     size_t max_nslots;
00139 
00140     dbg_return_if (pda == NULL, -1);
00141     dbg_return_if (!U_ARRAY_TYPE_IS_VALID(t), -1);
00142 
00143     da = u_zalloc(sizeof(u_array_t));
00144     warn_err_sif (da == NULL);
00145 
00146     da->type = t;
00147 
00148     if (nslots == 0)
00149         da->nslots = U_ARRAY_NSLOTS_DFL;
00150     else if (nslots > (max_nslots = MAX_NSLOTS(da)))
00151         da->nslots = max_nslots;
00152     else
00153         da->nslots = nslots;
00154 
00155     da->base = u_zalloc(da->nslots * sizeof_type[da->type]);
00156     warn_err_sif (da->base == NULL);
00157 
00158     *pda = da;
00159 
00160     return 0;
00161 err:
00162     u_array_free(da);
00163     return -1;
00164 }
00165 
00174 void u_array_free (u_array_t *da)
00175 {
00176     nop_return_if (da == NULL, );
00177 
00178     U_FREE(da->base);
00179     u_free(da);
00180 
00181     return;
00182 }
00183 
00193 int u_array_resize (u_array_t *da, size_t idx)
00194 {
00195     void *new_base;
00196     size_t new_nslots, max_nslots;
00197 
00198     dbg_return_if (da == NULL, -1);
00199 
00200     /* no need to resize, go out */
00201     dbg_return_if (idx < da->nslots, 0);
00202 
00203     /* can't go further, go out */
00204     dbg_return_if (idx >= (max_nslots = MAX_NSLOTS(da)) - 1, -1);
00205 
00206     /* decide how many new slots are needed */
00207     new_nslots = ((max_nslots - U_ARRAY_RESIZE_PAD - 1) >= idx) ?
00208         idx + U_ARRAY_RESIZE_PAD + 1 : max_nslots;
00209  
00210     /* try to realloc the array base pointer with the new size */
00211     new_base = u_realloc(da->base, new_nslots * sizeof_type[da->type]);
00212     warn_err_sif (new_base == NULL);
00213 
00214     da->base = new_base;
00215     da->nslots = new_nslots;
00216 
00217     return 0;
00218 err:
00219     return -1;
00220 }
00221 
00226 #define U_ARRAY_GETSET_F(pfx, dtype, ctype)    \
00227 int u_array_set##pfx (u_array_t *da, size_t idx, ctype v, ctype *pold)      \
00228 {                                                                           \
00229     ctype *ep;                                                              \
00230                                                                             \
00231     dbg_return_if (da == NULL, -1);                                         \
00232                                                                             \
00233     /* be strict over what we're assigning */                               \
00234     dbg_return_if (da->type != dtype, -1);                                  \
00235                                                                             \
00236     /* silently handle resize in case an element is set past the            \
00237      * actual index range */                                                \
00238     if (idx > da->nslots - 1)                                               \
00239         warn_err_if (u_array_resize(da, idx));                              \
00240                                                                             \
00241     /* get the selected slot */                                             \
00242     ep = (ctype *) da->base + idx;                                          \
00243                                                                             \
00244     /* if requested copy-out the old value before overriding it */          \
00245     if (pold)                                                               \
00246         *pold = *ep;                                                        \
00247                                                                             \
00248     /* assign */                                                            \
00249     *ep = v;                                                                \
00250                                                                             \
00251     return 0;                                                               \
00252 err:                                                                        \
00253     return -1;                                                              \
00254 }                                                                           \
00255                                                                             \
00256 int u_array_get##pfx (u_array_t *da, size_t idx, ctype *pv)                 \
00257 {                                                                           \
00258     ctype *ep;                                                              \
00259                                                                             \
00260     dbg_return_if (da == NULL, -1);                                         \
00261     dbg_return_if (pv == NULL, -1);                                         \
00262     /* be strict over what we're returning */                               \
00263     dbg_return_if (da->type != dtype, -1);                                  \
00264                                                                             \
00265     /* check overflow */                                                    \
00266     warn_err_if (idx > da->nslots - 1);                                     \
00267                                                                             \
00268     ep = (ctype *) da->base + idx;                                          \
00269                                                                             \
00270     *pv = *ep;                                                              \
00271                                                                             \
00272     return 0;                                                               \
00273 err:                                                                        \
00274     return -1;                                                              \
00275 }
00276 
00277 U_ARRAY_GETSET_F(_char, U_ARRAY_TYPE_CHAR, char)
00278 U_ARRAY_GETSET_F(_u_char, U_ARRAY_TYPE_U_CHAR, unsigned char)
00279 U_ARRAY_GETSET_F(_short, U_ARRAY_TYPE_SHORT, short)
00280 U_ARRAY_GETSET_F(_u_short, U_ARRAY_TYPE_U_SHORT, unsigned short)
00281 U_ARRAY_GETSET_F(_int, U_ARRAY_TYPE_INT, int)
00282 U_ARRAY_GETSET_F(_u_int, U_ARRAY_TYPE_U_INT, unsigned int)
00283 U_ARRAY_GETSET_F(_long, U_ARRAY_TYPE_LONG, long)
00284 U_ARRAY_GETSET_F(_u_long, U_ARRAY_TYPE_U_LONG, unsigned long)
00285 U_ARRAY_GETSET_F(_float, U_ARRAY_TYPE_FLOAT, float)
00286 U_ARRAY_GETSET_F(_double, U_ARRAY_TYPE_DOUBLE, double)
00287 
00288 #ifdef HAVE__BOOL
00289 U_ARRAY_GETSET_F(_bool, U_ARRAY_TYPE_BOOL, _Bool)
00290 #endif  /* HAVE__BOOL */
00291 
00292 #ifdef HAVE_LONG_LONG
00293 U_ARRAY_GETSET_F(_long_long, U_ARRAY_TYPE_LONG_LONG, long long)
00294 U_ARRAY_GETSET_F(_u_long_long, U_ARRAY_TYPE_U_LONG_LONG, unsigned long long)
00295 #endif  /* HAVE_LONG_LONG */
00296 
00297 #ifdef HAVE_INTMAX_T
00298 U_ARRAY_GETSET_F(_intmax, U_ARRAY_TYPE_INTMAX, intmax_t)
00299 U_ARRAY_GETSET_F(_u_intmax, U_ARRAY_TYPE_U_INTMAX, uintmax_t)
00300 #endif  /* HAVE_INTMAX_T */
00301 
00302 #ifdef HAVE_LONG_DOUBLE
00303 U_ARRAY_GETSET_F(_long_double, U_ARRAY_TYPE_LONG_DOUBLE, long double)
00304 #endif  /* HAVE_LONG_DOUBLE */
00305 
00306 #ifdef HAVE_FLOAT__COMPLEX
00307 U_ARRAY_GETSET_F(_float_complex, U_ARRAY_TYPE_FLOAT_COMPLEX, float _Complex)
00308 #endif  /* HAVE_FLOAT__COMPLEX */
00309 
00310 #ifdef HAVE_DOUBLE__COMPLEX
00311 U_ARRAY_GETSET_F(_double_complex, U_ARRAY_TYPE_DOUBLE_COMPLEX, double _Complex)
00312 #endif  /* HAVE_DOUBLE__COMPLEX */
00313 
00314 #ifdef HAVE_LONG_DOUBLE__COMPLEX
00315 U_ARRAY_GETSET_F(_long_double_complex, U_ARRAY_TYPE_LONG_DOUBLE_COMPLEX, long double _Complex)
00316 #endif  /* HAVE_LONG_DOUBLE__COMPLEX */
00317 
00356 void *u_array_set_ptr (u_array_t *da, size_t idx, void *v, int *prc)
00357 {
00358     void **ep, *old_ep;
00359 
00360     dbg_err_if (da == NULL);
00361     dbg_err_if (da->type != U_ARRAY_TYPE_PTR);
00362 
00363     if (idx > da->nslots - 1)
00364         dbg_err_if (u_array_resize (da, idx));
00365 
00366     ep = (void **) da->base + idx;
00367 
00368     /* save old value (could be NULL) */
00369     old_ep = *ep;
00370 
00371     /* overwrite with the supplied value */
00372     *ep = v;
00373 
00374     if (prc)
00375         *prc = 0;
00376 
00377     return old_ep;
00378 err:
00379     if (prc)
00380         *prc = -1;
00381     return NULL;
00382 }
00383 
00417 void *u_array_get_ptr (u_array_t *da, size_t idx, int *prc)
00418 {
00419     dbg_err_if (da == NULL);
00420     dbg_err_if (da->type != U_ARRAY_TYPE_PTR);
00421 
00422     warn_err_if (idx > da->nslots - 1);
00423 
00424     if (prc)
00425         *prc = 0;
00426 
00427     return *((void **) da->base + idx);
00428 err:
00429     if (prc)
00430         *prc = -1;
00431     return NULL;
00432 }

←Products
© 2005-2012 - KoanLogic S.r.l. - All rights reserved