[cvs] / netsukuku / src / buffer.h Repository:
ViewVC logotype

View of /netsukuku/src/buffer.h

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.10 - (download) (as text) (annotate)
Fri Feb 2 22:23:01 2007 UTC (3 years, 7 months ago) by alpt
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +39 -30 lines
* g2.c 67% done.
	* ext_rnode merged in rnode_list of 2radar.c
	* gnode2ip redesigned
	* (de)allocation functions for gmaps and ext-maps
* fixed array_grow()
    1 /* This file is part of Netsukuku
    2  * (c) Copyright 2005 Andrea Lo Pumo aka AlpT <alpt@freaknet.org>
    3  *
    4  * This source code is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License as published
    6  * by the Free Software Foundation; either version 2 of the License,
    7  * or (at your option) any later version.
    8  *
    9  * This source code is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   12  * Please refer to the GNU Public License for more details.
   13  *
   14  * You should have received a copy of the GNU Public License along with
   15  * this source code; if not, write to:
   16  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   17  *
   18  * --
   19  * buffer.c
   20  *
   21  * Various functions to manipulate buffers and arrays (see {-bufarr_t-}).
   22  */
   23 
   24 #ifndef BUFFER_H
   25 #define BUFFER_H
   26 
   27 /*
   28  * In bzero(3):
   29  * <<4.3BSD.  This function [bzero] is deprecated -- use memset in new
   30  *   programs.>>
   31  */
   32 #define setzero(_p, _sz)  memset((_p), 0, (_sz))
   33 
   34 /*\
   35  *
   36  * Buffer macros
   37  * =============
   38  *
   39  * The following macros are used to put/get data in a buffer.
   40  *
   41 \*/
   42 
   43 
   44 /*
   45  * memput
   46  *
   47  * It copies `__sz' bytes from `__src' to `__dst' and then increments the `__dst'
   48  * pointer of `__sz' bytes.
   49  *
   50  * The incremented `__dst' pointer is returned.
   51  *
   52  * Note: you can also use side expression, f.e.
   53  *   memput(buf++, src, (size+=sizeof(src));
   54  */
   55 #define memput(__dst, __src, __sz)          \
   56 ({                  \
   57   void **_mp_pdst=(void **)&(__dst);        \
   58   void *_mp_dst=*_mp_pdst, *_mp_src=(__src);      \
   59   size_t _mp_sz=(size_t)(__sz);         \
   60                   \
   61   memcpy(_mp_dst, _mp_src, _mp_sz);       \
   62   (*_mp_pdst)+=(_mp_sz);            \
   63   _mp_dst;              \
   64 })
   65 
   66 /*
   67  * memget
   68  *
   69  * the same of memput(), but it increments `__src' instead.
   70  *
   71  * The incremented `__src' pointer is returned.
   72  */
   73 #define memget(__dst, __src, __sz)          \
   74 ({                  \
   75   void **_mp_psrc=(void **)&(__src);        \
   76   void *_mp_dst=(__dst), *_mp_src=*_mp_psrc;      \
   77   size_t _mp_sz=(size_t)(__sz);         \
   78                   \
   79   memcpy(_mp_dst, _mp_src, _mp_sz);       \
   80   (*_mp_psrc)+=(_mp_sz);            \
   81   _mp_src;              \
   82 })
   83 
   84 /* use of hardcoded `_src' and `_dst' variable names */
   85 #define bufput(_src, _sz) (memput(buf, (_src), (_sz)))
   86 #define bufget(_dst, _sz) (memget((_dst), buf, (_sz)))
   87 
   88 
   89 
   90 /*\
   91  *
   92  * Buffer Array             |{bufarr_t}|
   93  * ============
   94  *
   95  * A buffer array is defined by these three elements:
   96  *
   97  *  atype *buf, int nmemb, int nalloc
   98  *
   99  * `atype' is the type the elements of the array, f.e. it can be "int",
  100  * "double" or whatever.
  101  *
  102  * `buf' is the pointer to the start of the array, i.e. the first element.
  103  *
  104  * `nmemb' is the number of elements stored in the array. buf[*nmemb-1] is the
  105  * last one.
  106  *
  107  * `nalloc' is the number of allocated elements of the array. It can be
  108  * greater than `nmemb'.
  109  *
  110  *
  111  * The macros defined below are used to manipulate a buffer array. Their
  112  * generic prototype is:
  113  *
  114  *  atype **_buf, int *_nmemb, int *_nalloc
  115  *
  116  * Where `_buf' is a pointer to a `buf' pointer described above.
  117  * `_nmemb' is a pointer to a `nmemb' variable,
  118  * `_nalloc' is a pointer to a `nalloc' variable.
  119  * Note that a macro may modify `*_buf', `*_nmemb' or `*_nalloc'.
  120  *
  121  *
  122  * WARNING: do not use expression as arguments to these macros. For example,
  123  *      DO NOT use array_replace(.., pos++, ...), but instead
  124  *      array_replace(.., pos, ...); pos++;
  125  *
  126  * Optional arguments
  127  * ------------------
  128  *
  129  * `_nmemb' and `_nalloc' must to two different variables.
  130  * If you don't want to specify `_nalloc', set it to 0.
  131  * If the `nalloc' argument passed to a macro is set to 0, then
  132  * the macro will assume that  *nmemb == *nalloc  and it will only
  133  * modify `*nmemb'.
  134  *
  135  * Notes on loops and buffer deletion
  136  * ----------------------------------
  137  *
  138  * Consider the following loop:
  139  *
  140  *  for(i=0; i<nmembs; i++)
  141  *    * Remove buffer[i]
  142  *    array_del(&buffer, &nmembs, i);
  143  *
  144  * What will happen?
  145  * The loop will skip over some elements. That's why:
  146  *
  147  *  the loop starts;
  148  *  i=0;
  149  *  buffer[0] is removed:
  150  *
  151  *  the array is shifted to the left by one:
  152  *    buffer[1] replaces buffer[0],
  153  *    buffer[2] replaces buffer[1],
  154  *    and so on... until
  155  *            buffer[nmembs-1] replaces buffer[nmembs-2]
  156  *
  157  *      nmembs is decremented by one
  158  *
  159  *  the loop continues;
  160  *  i=1;
  161  *  [!] buffer[1] is removed, however buffer[1] was substituted with
  162  *      buffer[2]! Thus, the original buffer[1] is not removed.
  163  *
  164  *      ...
  165  *
  166  * The correct loop is:
  167  *
  168  *
  169  *  for(i=0; i<nmembs; i++) {
  170  *    * Remove buffer[i]
  171  *    array_del(&buffer, &nmembs, i);
  172  *    * Adjust the index
  173  *    i--;
  174  *  }
  175  *
  176  * Note also that `nmembs' is modified during the call to `array_del'.
  177  *
  178  * If you want to simply destroy the array, use {-array_destroy-}
  179 \*/
  180 
  181 /*
  182  * array_replace
  183  * -------------
  184  *
  185  * Copies the data pointed by _new to (*_buf)[_pos] and returns &(*_buf)[pos]
  186  * Note: `_pos' must be < `*nalloc', otherwise an overflow will occur.
  187  *
  188  * Usage:
  189  *  array_replace(&buf_array_ptr, pos, new_element_ptr);
  190  */
  191 #define array_replace(_buf, _pos, _new)         \
  192 ({                  \
  193   void *_ar_ptr=(*(_buf))[(_pos)];        \
  194   memcpy(_ar_ptr, (_new), sizeof(typeof(*(_new))));   \
  195   (typeof(*(_buf)) _ar_ptr;         \
  196 })
  197 
  198 /*
  199  * array_insert
  200  * ------------
  201  *
  202  * The same of {-array_replace-}, but with an additional check.
  203  * :fatal(): is called if _pos is greater than *_nalloc
  204  *
  205  * Usage:
  206  *  array_insert(&buf_array_ptr, &nalloc_var, new_elem_ptr);
  207  */
  208 #define array_insert(_buf, _nalloc, _pos, _new)       \
  209 ({                  \
  210   if(_pos >= *(_nalloc) || _pos < 0)        \
  211     fatal(ERROR_MSG"Array overflow: _nalloc %d, _pos %d", \
  212       ERROR_POS, _nalloc, _pos);      \
  213                   \
  214   array_replace(_buf, _pos, _new);        \
  215 })
  216 
  217 
  218 /*
  219  * array_grow
  220  * ----------
  221  *
  222  * It enlarges the array by allocating `_count' elements and appending them at
  223  * its end.
  224  * `*_nalloc' is incremented and `*_buf' is set to point to the new start of the
  225  * array (since :xrealloc(): is used).
  226  *
  227  * If `_count' is zero, then the array will be shrinked/enlarged to exactly
  228  * `*_nalloc' elements.
  229  *
  230  * Note: if `_count' is a negative value and _nalloc-_count >= 0, then
  231  * the array is shrinked (see {-array_shrink-}).
  232  *
  233  * Usage:
  234  *  array_grow(&buf_array_ptr, &nalloc_var, count);
  235  *    or
  236  *  array_grow(&buf_array_ptr, &nalloc_var, 0);
  237  */
  238 #define array_grow(_buf, _nalloc, _count)                         \
  239 do {                  \
  240   (*_nalloc)+=(_count);           \
  241   if((*_nalloc) < 0)            \
  242     fatal(ERROR_MSG"Array underflow: _count %d",    \
  243       ERROR_POS, _count);       \
  244   *(_buf)=xrealloc(*(_buf), sizeof(typeof(**(_buf)))*(*_nalloc)); \
  245 } while(0)
  246 
  247 /*
  248  * array_shrink
  249  * ------------
  250  *
  251  * Deallocates and destroys the last `_count' elements of the array.
  252  * `*_buf' is set to point to the new start of the array (since :xrealloc():
  253  * is used).
  254  *
  255  * Usage:
  256  *  array_shrink(&buf_array_ptr, &nmemb_var, &nalloc_var, count);
  257  */
  258 #define array_shrink(_buf, _nalloc, _count)       \
  259     array_grow(_buf, _nalloc, -abs(_count))
  260 
  261 
  262 /*
  263  * Trick to handle NULL pointers.
  264  * If you want to understand it, see where it is
  265  * used: {-__array_fake_nalloc:"r-}
  266  */
  267 #define __array_fake_nalloc(__nmemb, __nalloc)        \
  268   typeof(__nmemb) _ag_na = (__nalloc);        \
  269   typeof(*(__nmemb)) _ag_fake_na;         \
  270   if(!_ag_na) {             \
  271     _ag_fake_na = *(__nmemb);       \
  272     _ag_na = &_ag_fake_na;          \
  273   }
  274 
  275 /*
  276  * Private macro. See {-array_add-} and {-array_add_more-} below.
  277  */
  278 #define array_add_grow(_buf, _nmemb, _nalloc, _new, _newalloc)    \
  279 ({                  \
  280   __array_fake_nalloc(_nmemb, _nalloc);       \
  281                   \
  282   (*(_nmemb))++;              \
  283                   \
  284   if(*(_nmemb) > *(_ag_na))         \
  285     array_grow(_buf, _ag_na, _newalloc);      \
  286                   \
  287   array_replace(_buf, (*(_nmemb))-1, _new);     \
  288 )}
  289 
  290 
  291 /*
  292  * array_add
  293  * ---------
  294  *
  295  * Adds a new element at the end of the array and copies in it
  296  * the data pointed by `_new'.
  297  *
  298  * `*_nmemb' is always incremented by one. If necessary, a new
  299  * element is allocated at the end of the array and `*_nalloc' is incremented
  300  * by one.
  301  *
  302  * The pointer to the new inserted element is returned.
  303  *
  304  * Exception:
  305  * if the `_nalloc' argument is set to 0, then this macro will assume that
  306  * `*_nmemb' == `*_nalloc', and only `*_nmemb' will be incremented.
  307  *
  308  * Usage:
  309  *  array_add(&buf_array_ptr, &nmemb_var, &nalloc_var, new_elem_ptr);
  310  * or
  311  *  array_add(&buf_array_ptr, &nmemb_var, 0, new_element_ptr);
  312  */
  313 #define array_add(_buf, _nmemb, _nalloc, _new)        \
  314     array_add_grow(_buf, _nmemb, _nalloc, _new, 1)
  315 
  316 /*
  317  * array_add_more
  318  * --------------
  319  *
  320  * The same of {-array_add-}, but instead of allocating just one new element, it
  321  * allocates _nmemb/2+1 elements.
  322  * This is useful if array_add_more() is called many times.
  323  */
  324 #define array_add_more(_buf, _nmemb, _nalloc, _new)     \
  325     array_add_grow(_buf, _nmemb, _nalloc, _new, (_nmemb)/2+1)
  326 
  327 
  328 /*
  329  * array_del
  330  * ---------
  331  *
  332  * Deletes the element at position `_pos'.
  333  * The element is deleted by copying the last element of the array over it,
  334  * i.e. we copy (*_buf)[*_nmemb-1] over (*_buf)[_pos]. In this way, the last
  335  * element of the array is reusable.
  336  * `*_nmemb' is decremented by one.
  337  *
  338  * Note that this macro doesn't deallocate anything, see {-array_del_free-} for
  339  * that.
  340  *
  341  * If `_pos' isn't a valid value, an array overflow occurs and :fatal(): is
  342  * called.
  343  */
  344 #define array_del(_buf, _nmemb, _pos)         \
  345 do {                  \
  346   if(_pos >= *(_nmemb) || _pos < 0)       \
  347     fatal(ERROR_MSG "Array overflow: _nmemb %d, _pos %d", \
  348       ERROR_POS, *(_nmemb), *(_pos));     \
  349   (*(_nmemb))--;              \
  350   if(_pos < *(_nmemb))            \
  351     memcpy( (*(_buf))[(_pos)], (*(_buf))[*(_nmemb)],  \
  352         sizeof(typeof(**(_buf))) );   \
  353 } while(0)
  354 
  355 
  356 /*
  357  * array_del_free
  358  * --------------
  359  *
  360  * The same of {-array_del-}, but deallocates one element from the array.
  361  * `*_buf' is set to point to the new start of the array (since :xrealloc():
  362  * is used).
  363  *
  364  * Exception:
  365  * if the `_nalloc' argument is set to 0, then this macro will assume that
  366  * `*_nmemb' == `*_nalloc', and only `*_nmemb' will be decremented.
  367  *
  368  * Usage:
  369  *  array_del_free(&buf_array_ptr, &nmemb_var, &nalloc_var, pos);
  370  * or
  371  *  array_del_free(&buf_array_ptr, &nmemb_var, 0, pos);
  372  */
  373 #define array_del_free(_buf, _nmemb, _nalloc, _pos)     \
  374 do {                  \
  375   __array_fake_nalloc(_nmemb, _nalloc);       \
  376                   \
  377   array_del(_buf, _nmemb, _pos);          \
  378   array_shrink(_buf, _ag_na, 1);          \
  379 } while(0)
  380 
  381 /*
  382  * array_rem
  383  * ---------
  384  *
  385  * Deletes the element at position `_pos'.
  386  * The element is deleted by shifting to the left all its successive elements.
  387  * In this way, the order of the array is preserved.
  388  * This is useful if the array has been ordered with qsort(3), however this is
  389  * less efficient than {-array_del-}.
  390  *
  391  * Note that this macro doesn't deallocate anything, see {-array_rem_free-} for
  392  * that. Moreover, once the array is shifted, the data stored in
  393  * (*_buf)[*_nmemb] is not touched. You may want to zero it. Example:
  394  *
  395  *  array_rem(&buf_array_ptr, &nmemb_var, pos);
  396  *  setzero( buf_array_ptr[nmemb_var], sizeof(typeof(*buf_array_ptr)) );
  397  *
  398  * If `_pos' isn't a valid value, an array overflow occurs and :fatal(): is
  399  * called.
  400  */
  401 #define array_rem(_buf, _nmemb, _pos)         \
  402 do {                  \
  403   if(_pos >= *(_nmemb) || _pos < 0)       \
  404     fatal(ERROR_MSG"Array overflow: _nmemb %d, _pos %d",  \
  405       ERROR_POS, *(_nmemb), _pos);      \
  406   /* Shift the array */           \
  407   if(_pos < (*(_nmemb))-1)          \
  408                 memmove( &(*(_buf))[_pos], &(*(_buf))[_pos+1],    \
  409                       sizeof(typeof(**(_buf))) * ((*(_nmemb))-_pos-1)); \
  410   (*(_nmemb))--;              \
  411 } while(0)
  412 
  413 /*
  414  * array_rem_free
  415  * --------------
  416  *
  417  * The same of {-array_rem-}, but deallocates one element from the array.
  418  * `*_buf' is set to point to the new start of the array (since :xrealloc():
  419  * is used).
  420  */
  421 #define array_rem_free(_buf, _nmemb, _nalloc, _pos)     \
  422 do {                  \
  423   __array_fake_nalloc(_nmemb, _nalloc);       \
  424   array_rem(_buf, _nmemb, _pos);          \
  425   array_shrink(_buf, _ag_na, 1);          \
  426 } while(0)
  427 
  428 /*
  429  * array_destroy
  430  * -------------
  431  *
  432  * Deallocates the whole array and sets `*_nmemb', `*_nalloc' to zero.
  433  *
  434  * `_nmemb' or `_nalloc' can be 0.
  435  *
  436  * Usage:
  437  *  array_destroy(&buf_array_ptr, &nmemb_var, &nalloc_var);
  438  * or
  439  *  array_destroy(&buf_array_ptr, 0, 0);
  440  */
  441 #define array_destroy(_buf, _nmemb, _nalloc)        \
  442 do {                  \
  443   if( *(_buf) && (!(_nmemb) || *(_nmemb) > 0) )     \
  444     xfree(*(_buf));           \
  445   _nmemb && *(_nmemb)=0;            \
  446   _nalloc && *(_nalloc)=0;          \
  447 } while(0)
  448 
  449 /*
  450  * array_bzero
  451  * -----------
  452  *
  453  * Sets `_count' elements of the array to 0.
  454  * If `_count' == -1, then the whole array is zeroed.
  455  * If `_count' > `*_nalloc', :fatal(): is called.
  456  *
  457  * Usage:
  458  *  array_bzero(&buf_array_ptr, &nalloc_var, count);
  459  * or
  460  *  array_bzero(&buf_array_ptr, &nalloc_var, -1);
  461  */
  462 #define array_bzero(_buf, _nalloc, _count)        \
  463 do {                  \
  464   if((_count) > *(_nalloc))         \
  465     fatal(ERROR_MSG "Array overflow: _count %d",    \
  466       ERROR_POS, (_count));       \
  467                   \
  468   setzero(*(_buf), sizeof(typeof(**(_buf))) *       \
  469         (_count == -1 ? *(_nalloc) : _count) ); \
  470 } while(0)
  471 
  472 
  473 /*\
  474  *   * * *  Functions declaration  * * *
  475 \*/
  476 int is_bufzero(const void *a, int sz);
  477 
  478 #endif /*BUFFER_H*/

alpt (at) freaknet (dot) org
ViewVC Help
Powered by ViewVC 1.1-dev