Provided by: libstatgrab-dev_0.92-2_amd64 bug


       sg_vector_create,   sg_vector_clear,  sg_vector_resize,  sg_vector_free,  sg_vector_clone,
       sg_vector_clone_into,    sg_vector_compute_diff,    sg_prove_vector,     sg_get_nelements,
       sg_free_stats_buf - statgrab vector management


       #include "statgrab.h"
       #include "vector.h"

       struct sg_vector *sg_vector_create (size_t block_size, size_t alloc_count, size_t
                                          initial_used, const sg_vector_init_info * const info);

       void sg_vector_clear (struct sg_vector *vector);

       struct sg_vector *sg_vector_resize (struct sg_vector *vector);

       void sg_vector_free (struct sg_vector *vector);

       struct sg_vector *sg_vector_clone (const struct sg_vector *src);

       sg_error sg_vector_clone_into (struct sg_vector **dest, const struct sg_vector *src);

       sg_error sg_vector_compute_diff (struct sg_vector **dest, const struct sg_vector
                                       *cur_vector, const struct sg_vector *last_vector);

       sg_error sg_prove_vector (const struct sg_vector *vec);

       size_t sg_get_nelements (const void *data);

       sg_error sg_free_stats_buf (void *data);


       sg_vector_create()  allocates  and  initialises  a  new  statgrab vector with initial_used
       elements ready for use. Space for alloc_count elements is initially  allocated  (to  avoid
       too  many  calls  to  realloc()  during  later  sg_vector_resize()  calls).  The  value of
       block_size must be a power of 2, it's rounded up to the next power of 2 when it's not.  If
       alloc_count  is  not  a  multiple  of  block_size, it's rounded up to the next multiple of
       block_size. It returns a pointer to the newly created vector.

       sg_vector_clear() destroys all elements contained in the  given  vector.  In  opposite  to
       sg_vector_resize( x, 0 ) the allocated size of the vector remains untouched.

       sg_vector_resize()  increases  or  decreases  the  amount  of  allocated  elements  in the
       specified  vector.  The  amount  of  allocated  elements  is  always  a  multiple  of  the
       intialisation parameter block_size. In the special case, sg_vector_resize() is called with
       0 in argument new_count, the vector is freed after all vector elements had been destroyed.
       It returns the pointer to the resized vector.

       sg_vector_free() destroys all vector elements and deallocates the storage belonging to the
       given vector.

       sg_vector_clone() clones all elements of the given vector into a new vector  created  with
       the same specification as the referenced one. It returns a pointer to the cloned vector.

       sg_vector_clone_into()  clones  all  elements  of  the  given source vector into the given
       target vector. The target vector must be created for the same element  data  type  as  the
       source vector. It returns an error code != to SG_ERROR_NONE if something went wrong.

       sg_vector_compute_diff()  computes  a  difference  vector  between  the  vector containing
       current statistics and another vector containing older statistics. If an element exists in
       the  current vector but not in the opposite one, it's cloned into the result vector. If an
       element exists only in the opposite vector,  it  doesn't  appear  in  the  target  vector.
       sg_vector_compute_diff()  returns  an  error  code  !=  to SG_ERROR_NONE if something went

       sg_prove_vector() proves whether a pointer to a vector really points to a vector. In  case
       the  given  vector  pointer  points  to  corrupted  data,  the  program  is  aborted. When
       sg_prove_vector() returns, it returns SG_ERROR_NONE.

       sg_get_nelements() returns the number of elements the given data area,  encompasses  by  a
       statgrab vector, contains. The vector head is internally calculated from the given pointer
       to the first vector element.

       sg_free_stats_buf() frees the vector emcompassing the given data area.


       Except sg_get_nelements() and sg_free_stats_buf() none of above functions  can  be  called
       from  outside  of  the  libstatgrab sources. The documented structures and APIs may change
       without warning. The description of all other API is intended to be read from  libstatgrab
       developers only.

       Each vector is created from two elements: the vector information and the list of elements:

       template <class T, class Impl>
       struct sg_vector {
               size_t used_count;
               size_t alloc_count;
               size_t block_shift;
               Impl vector_implementation;
               T elements[alloc_count];

       Of course, it is not valid C, so being tricky was the solution:

       typedef struct sg_vector {
            size_t used_count;
            size_t alloc_count;
            size_t block_shift;
            struct sg_vector_init_info info;
       } sg_vector;

       struct sg_vector_size_helper {
            struct sg_vector v;
            long long ll;

       #define VECTOR_SIZE offsetof(struct sg_vector_size_helper,ll)

       /* Return the data ptr of a vector */
       #define VECTOR_DATA(vector) \
            (vector ? (void *)(((char *)vector)+VECTOR_SIZE) : NULL)

       #define VECTOR_ADDR_ARITH(ptr) \
            (sg_vector *)(((char *)(ptr))-VECTOR_SIZE)
       /* Return the vector for a data */
       #define VECTOR_ADDRESS(ptr) \
            ((ptr) ? (SG_ERROR_NONE == sg_prove_vector(VECTOR_ADDR_ARITH(ptr)) ? VECTOR_ADDR_ARITH(ptr) : NULL ) : NULL)

       This  also  allows  user functions as sg_get_nelements() and sg_free_stats_buf() to switch
       easily between the vector structure and the content.

       As  mentioned,  the  vector  implementation  uses  strategies  from  the  object  oriented
       programming  concept  named  "polymorphism".   A  vector  is  described  by a small object
       containing inherent attributes like element size and a bunch of "virtual  methods"  to  do
       element related tasks like initialising or destroying elements.

       typedef void (*vector_init_function)(void *item);
       typedef sg_error (*vector_copy_function)(const void *src, void *dst);
       typedef sg_error (*vector_compute_diff_function)(void *dst, const void *src);
       typedef int (*vector_compare_function)(const void *a, const void *b);
       typedef void (*vector_destroy_function)(void *item);

       struct sg_vector_init_info {
               size_t item_size;
               vector_init_function init_fn;
               vector_copy_function copy_fn;
               vector_compute_diff_function compute_diff_fn;
               vector_compare_function compare_fn;
               vector_destroy_function destroy_fn;

       The  instances  of  struct  sg_vector_init_info are conceptional statically initialised by
       using    either    the    preprocessor    macro    VECTOR_INIT_INFO_FULL_INIT(type)     or
       VECTOR_INIT_INFO_EMPTY_INIT(type).  Here're some examples to demonstrate how it's meant:

       Initialising CPU statistics vector description


       Initialising Host-Info statistics vector description

       static void sg_os_stats_item_init(sg_os_stats *d);
       static void sg_os_stats_item_destroy(sg_os_stats *d);

       #define sg_os_stats_item_copy NULL
       #define sg_os_stats_item_compute_diff NULL
       #define sg_os_stats_item_compare NULL


       Initialising Disk-IO statistics vector description

       static void sg_disk_io_stats_item_init(sg_disk_io_stats *d);
       static sg_error sg_disk_io_stats_item_copy(sg_disk_io_stats *d, const sg_disk_io_stats *s);
       static sg_error sg_disk_io_stats_item_compute_diff(const sg_disk_io_stats *s, sg_disk_io_stats *d);
       static int sg_disk_io_stats_item_compare(const sg_disk_io_stats *a, const sg_disk_io_stats *b);
       static void sg_disk_io_stats_item_destroy(sg_disk_io_stats *d);


       To simplify the working with the vector management functions, some preprocessor macros are
       available. They are shown here as if they were functions to ease understanding.

       struct sg_vector *VECTOR_CREATE (identifier type, size_t block_size);

       void VECTOR_CLEAR (struct sg_vector *vector);

       struct sg_vector *VECTOR_CREATE_OR_RESIZE (struct sg_vector *vector, size_t new_count,
                                                 identifier type);

       void VECTOR_UPDATE (struct sg_vector **vectorptr, size_t new_count, datatype *data,
                          identifier datatype);

       void VECTOR_ITEM_COUNT (struct sg_vector *vector);

       VECTOR_CREATE() calls sg_vector_create() with alloc_count = block_size and initial_used  =
       0 using the vector specialisation type##_vector_init_info.

       VECTOR_CLEAR() simply calls sg_vector_clear(). This macro exists only for conformity.

       VECTOR_CREATE_OR_RESIZE() calls sg_vector_create() when the given vector pointer points to
       NULL or sg_vector_resize() otherwise. The result of the appropriate function is returned.

       VECTOR_UPDATE() calls VECTOR_CREATE_OR_RESIZE() and sets data to the first element of  the
       resulting   vector   when   a   non-NULL   pointer   got,   to   NULL   otherwise.    When
       VECTOR_CREATE_OR_RESIZE() returns a NULL pointer and new_count is not equal to  0  (zero),
       the  intructions from the macro VECTOR_UPDATE_ERROR_CLEANUP are executed to cleanup before
       returning from current subroutine with the error which has been occurred.

       VECTOR_ITEM_COUNT() returns 0 for a non-existing vector (vector == 0) and  the  number  of
       containing elements otherwise.


       Beside  error  codes, the return values, if any, are always a pointer to vector structures
       (struct sg_vector *).