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( | block_size, | |
alloc_count, | ||
initial_used, | ||
info) ; |
size_t block_size
;size_t alloc_count
;size_t initial_used
;const sg_vector_init_info * const info
;void sg_vector_clear( | vector) ; |
struct sg_vector *vector
;struct sg_vector *sg_vector_resize( | vector) ; |
struct sg_vector *vector
;void sg_vector_free( | vector) ; |
struct sg_vector *vector
;struct sg_vector *sg_vector_clone( | src) ; |
const struct sg_vector *src
;sg_error sg_vector_clone_into( | dest, | |
src) ; |
struct sg_vector **dest
;const struct sg_vector *src
;sg_error sg_vector_compute_diff( | dest, | |
cur_vector, | ||
last_vector) ; |
struct sg_vector **dest
;const struct sg_vector *cur_vector
;const struct sg_vector *last_vector
;sg_error sg_prove_vector( | vec) ; |
const struct sg_vector *vec
;size_t sg_get_nelements( | data) ; |
const void *data
;sg_error sg_free_stats_buf( | data) ; |
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 initialisation 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 wrong.
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:
Example 1. Initialising CPU statistics vector description
VECTOR_INIT_INFO_EMPTY_INIT(sg_cpu_stats);
Example 2. 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 VECTOR_INIT_INFO_FULL_INIT(sg_os_stats);
Example 3. 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); VECTOR_INIT_INFO_FULL_INIT(sg_disk_io_stats);
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( | type, | |
block_size) ; |
identifier type
;size_t block_size
;void VECTOR_CLEAR( | vector) ; |
struct sg_vector *vector
;struct sg_vector *VECTOR_CREATE_OR_RESIZE( | vector, | |
new_count, | ||
type) ; |
struct sg_vector *vector
;size_t new_count
;identifier type
;void VECTOR_UPDATE( | vectorptr, | |
new_count, | ||
data, | ||
datatype) ; |
struct sg_vector **vectorptr
;size_t new_count
;datatype *data
;identifier datatype
;void VECTOR_ITEM_COUNT( | vector) ; |
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 instructions 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.