mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Use commit 0e1e780fd6f18ce93119061e36a4fca9711bc020 Excluded multibuild folder, as this caused git issues
1593 lines
44 KiB
C++
1593 lines
44 KiB
C++
/*
|
||
Copyright (C) 2011 Equinor ASA, Norway.
|
||
|
||
The file 'vector_template.c' is part of ERT - Ensemble based Reservoir Tool.
|
||
|
||
ERT is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation, either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
||
See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||
for more details.
|
||
*/
|
||
|
||
/**
|
||
This file implements a very simple vector functionality. The vector
|
||
is charactereized by the following:
|
||
|
||
o The content is only fundamental scalar types, like double, int
|
||
or bool. If you want a vector of compositie types use the
|
||
vector_type implementation.
|
||
|
||
o The vector will grow as needed. You can safely set any index in
|
||
the vector, and it will automatically grow. However - this might
|
||
lead to 'holes' - these will be filled with the default value.
|
||
|
||
o The implementation is in terms of a @TYPE@, the following sed
|
||
one-liners will then produce proper source and header files:
|
||
|
||
sed -e's/@TYPE@/int/g' vector_template.c > int_vector.c
|
||
sed -e's/@TYPE@/int/g' vector_template.h > int_vector.h
|
||
|
||
|
||
Illustration of the interplay of size, alloc_size and default value.
|
||
|
||
|
||
1. int_vector_type * vector = int_vector_alloc(2 , 77);
|
||
2. int_vector_append(vector , 1);
|
||
3. int_vector_append(vector , 0);
|
||
4. int_vector_append(vector , 12);
|
||
5. int_vector_iset(vector , 6 , 78);
|
||
6. int_vector_set_default( vector , 99 );
|
||
|
||
------------------------------------
|
||
|
||
<20>-----<2D>-----<2D>
|
||
1. | 77 | 77 | size = 0, alloc_size = 2
|
||
<20>-----<2D>-----<2D>
|
||
|
||
<20>-----<2D>-----<2D>
|
||
2. | 1 | 77 | size = 1, alloc_size = 2
|
||
<20>-----<2D>-----<2D>
|
||
|
||
<20>-----<2D>-----<2D>
|
||
3. | 1 | 0 | size = 2, alloc_size = 2
|
||
<20>-----<2D>-----<2D>
|
||
|
||
<20>-----<2D>-----<2D>-----<2D>-----<2D>
|
||
4. | 1 | 0 | 12 | 77 | size = 3, alloc_size = 4
|
||
<20>-----<2D>-----<2D>-----<2D>-----<2D>
|
||
|
||
<20>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>
|
||
5. | 1 | 0 | 12 | 77 | 77 | 77 | 78 | 77 | 77 | 77 | 77 | 77 | 77 | 77 | 77 | 77 | size = 7, alloc_size = 12, default = 77
|
||
<20>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>
|
||
|
||
<20>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>
|
||
6. | 1 | 0 | 12 | 77 | 77 | 77 | 78 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | 99 | size = 7, alloc_size = 12, default = 99
|
||
<20>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>-----<2D>
|
||
|
||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||
|
||
|
||
1. In point 4. above - if you ask the vector for it's size you
|
||
will get 3, and int_vector_iget(vector, 3) will fail because
|
||
that is beyound the end of the vector.
|
||
|
||
2. The size of the vector is the index (+1) of the last validly
|
||
set element in the vector.
|
||
|
||
3. In point 5 above we have grown the vector quite a lot to be
|
||
able to write in index 6, as a results there are now many slots
|
||
in the vector which contain the default value - i.e. 77 in this
|
||
case.
|
||
|
||
4. In point 6 we change the default value 77 -> 99, then all the
|
||
77 values from position 7 and onwards are changed to 99; the 77
|
||
values in positions 3,4 & 5 are not touched.
|
||
|
||
|
||
*/
|
||
|
||
#include <string.h>
|
||
#include <stdbool.h>
|
||
#include <stdlib.h>
|
||
#include <math.h>
|
||
|
||
#include <ert/util/type_macros.hpp>
|
||
#include <ert/util/util.h>
|
||
#include <ert/util/@TYPE@_vector.hpp>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
static const char * string_type = "@TYPE@";
|
||
#define TYPE_VECTOR_ID ((int *) string_type )[0]
|
||
|
||
struct @TYPE@_vector_struct {
|
||
UTIL_TYPE_ID_DECLARATION;
|
||
int alloc_size; /* The allocated size of data. */
|
||
int size; /* The index of the last valid - i.e. actively set - element in the vector. */
|
||
@TYPE@ default_value; /* The data vector is initialized with this value. */
|
||
@TYPE@ * data; /* The actual data. */
|
||
bool data_owner; /* Is the vector owner of the the actual storage data?
|
||
If this is false the vector can not be resized. */
|
||
bool read_only;
|
||
};
|
||
|
||
|
||
/**
|
||
This datatype is used when allocating a permutation list
|
||
corresponding to a sorted a xxx_vector instance. This permutation
|
||
list can then be used to reorder several xxx_vector instances.
|
||
*/
|
||
|
||
typedef struct {
|
||
int index;
|
||
@TYPE@ value;
|
||
} sort_node_type;
|
||
|
||
|
||
UTIL_SAFE_CAST_FUNCTION(@TYPE@_vector , TYPE_VECTOR_ID);
|
||
UTIL_IS_INSTANCE_FUNCTION(@TYPE@_vector , TYPE_VECTOR_ID);
|
||
|
||
|
||
static void @TYPE@_vector_realloc_data__(@TYPE@_vector_type * vector , int new_alloc_size, @TYPE@ default_value) {
|
||
if (new_alloc_size != vector->alloc_size) {
|
||
if (vector->data_owner) {
|
||
if (new_alloc_size > 0) {
|
||
int i;
|
||
vector->data = (@TYPE@*)util_realloc(vector->data , new_alloc_size * sizeof * vector->data );
|
||
for (i=vector->alloc_size; i < new_alloc_size; i++)
|
||
vector->data[i] = default_value;
|
||
} else {
|
||
if (vector->alloc_size > 0) {
|
||
free(vector->data);
|
||
vector->data = NULL;
|
||
}
|
||
}
|
||
vector->alloc_size = new_alloc_size;
|
||
} else
|
||
util_abort("%s: tried to change the storage are for a shared data segment \n",__func__);
|
||
}
|
||
}
|
||
|
||
|
||
static void @TYPE@_vector_memmove(@TYPE@_vector_type * vector , int offset , int shift) {
|
||
if ((shift + offset) < 0)
|
||
util_abort("%s: offset:%d left_shift:%d - invalid \n",__func__ , offset , -shift);
|
||
|
||
if ((shift + vector->size > vector->alloc_size))
|
||
@TYPE@_vector_realloc_data__( vector , util_int_min( 2*vector->alloc_size , shift + vector->size ), vector->default_value);
|
||
|
||
{
|
||
size_t move_size = (vector->size - offset) * sizeof(@TYPE@);
|
||
@TYPE@ * target = &vector->data[offset + shift];
|
||
const @TYPE@ * src = &vector->data[offset];
|
||
memmove( target , src , move_size );
|
||
|
||
vector->size += shift;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
static void @TYPE@_vector_assert_index(const @TYPE@_vector_type * vector , int index) {
|
||
if ((index < 0) || (index >= vector->size))
|
||
util_abort("%s: index:%d invalid. Valid interval: [0,%d>.\n",__func__ , index , vector->size);
|
||
}
|
||
|
||
|
||
|
||
|
||
static @TYPE@_vector_type * @TYPE@_vector_alloc__(int init_size , @TYPE@ default_value, @TYPE@ * data, int alloc_size , bool data_owner ) {
|
||
@TYPE@_vector_type * vector = (@TYPE@_vector_type*)util_malloc( sizeof * vector );
|
||
UTIL_TYPE_ID_INIT( vector , TYPE_VECTOR_ID);
|
||
vector->default_value = default_value;
|
||
|
||
/**
|
||
Not all combinations of (data, alloc_size, data_owner) are valid:
|
||
|
||
1. Creating a new vector instance with fresh storage allocation
|
||
from @TYPE@_vector_alloc():
|
||
|
||
data == NULL
|
||
alloc_size == 0
|
||
data_owner == true
|
||
|
||
|
||
2. Creating a shared wrapper from the @TYPE@_vector_alloc_shared_wrapper():
|
||
|
||
data != NULL
|
||
data_size > 0
|
||
data_owner == false
|
||
|
||
|
||
3. Creating a private wrapper which steals the input data from
|
||
@TYPE@_vector_alloc_private_wrapper():
|
||
|
||
data != NULL
|
||
data_size > 0
|
||
data_owner == true
|
||
|
||
*/
|
||
|
||
if (data == NULL) { /* Case 1: */
|
||
vector->data = NULL;
|
||
vector->data_owner = true; /* The input values alloc_size and */
|
||
vector->alloc_size = 0; /* data_owner are not even consulted. */
|
||
} else { /* Case 2 & 3 */
|
||
vector->data = data;
|
||
vector->data_owner = data_owner;
|
||
vector->alloc_size = alloc_size;
|
||
}
|
||
vector->size = 0;
|
||
|
||
@TYPE@_vector_set_read_only( vector , false );
|
||
if (init_size > 0)
|
||
@TYPE@_vector_resize( vector , init_size , default_value ); /* Filling up the init size elements with the default value */
|
||
|
||
return vector;
|
||
}
|
||
|
||
|
||
/**
|
||
The alloc_size argument is just a hint - the vector will grow as
|
||
needed.
|
||
*/
|
||
|
||
@TYPE@_vector_type * @TYPE@_vector_alloc(int init_size , @TYPE@ default_value) {
|
||
@TYPE@_vector_type * vector = @TYPE@_vector_alloc__( init_size , default_value , NULL , 0 , true );
|
||
return vector;
|
||
}
|
||
|
||
|
||
/**
|
||
new_size < current_size: The trailing elements will be lost
|
||
|
||
new_size > current_size: The vector will grow by adding default elements at the end.
|
||
*/
|
||
|
||
void @TYPE@_vector_resize( @TYPE@_vector_type * vector , int new_size, @TYPE@ default_value ) {
|
||
if (new_size > vector->size) {
|
||
if (new_size > vector->alloc_size) {
|
||
for (int i = vector->size; i < vector->alloc_size; i++)
|
||
vector->data[i] = default_value;
|
||
@TYPE@_vector_realloc_data__( vector, 2 * new_size, default_value);
|
||
}
|
||
else
|
||
for (int i = vector->size; i < new_size; i++)
|
||
vector->data[i] = default_value;
|
||
}
|
||
vector->size = new_size;
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_set_read_only( @TYPE@_vector_type * vector , bool read_only) {
|
||
vector->read_only = read_only;
|
||
}
|
||
|
||
bool @TYPE@_vector_get_read_only( const @TYPE@_vector_type * vector ) {
|
||
return vector->read_only;
|
||
}
|
||
|
||
|
||
static void @TYPE@_vector_assert_writable( const @TYPE@_vector_type * vector ) {
|
||
if (vector->read_only)
|
||
util_abort("%s: Sorry - tried to modify a read_only vector instance.\n",__func__);
|
||
}
|
||
|
||
/**
|
||
This function will allocate a shared wrapper around the input
|
||
pointer data. The vector implementation will work transparently
|
||
with the input data, but the data will not be reallocated, and also
|
||
not freed when exiting, this implies that it is safe (memory wise)
|
||
to work with the memory location pointed to by data from somewhere
|
||
else as well.
|
||
|
||
Vector wrappers allocated this way can NOT grow, and will fail HARD
|
||
if a resize beyond alloc_size is attempted - check with
|
||
@TYPE@_vector_growable()
|
||
*/
|
||
|
||
|
||
@TYPE@_vector_type * @TYPE@_vector_alloc_shared_wrapper(int init_size, @TYPE@ default_value , @TYPE@ * data , int alloc_size) {
|
||
return @TYPE@_vector_alloc__( init_size , default_value , data , alloc_size , false );
|
||
}
|
||
|
||
|
||
/**
|
||
This function will allocate a vector wrapper around the input
|
||
pointer data. The input data will be hijacked by the vector
|
||
implementation, and the vector will continue like a 100% normal
|
||
vector instance, that includes the capability to resize the data
|
||
area, and the data are will also be freed when the vector is freed.
|
||
|
||
Observe that it is (in general) NOT safe to continue to use the
|
||
data pointer from an external scope.
|
||
*/
|
||
|
||
|
||
@TYPE@_vector_type * @TYPE@_vector_alloc_private_wrapper(int init_size, @TYPE@ default_value , @TYPE@ * data , int alloc_size) {
|
||
return @TYPE@_vector_alloc__( init_size , default_value , data , alloc_size , false );
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
This function will copy a block starting at index @src_offset in
|
||
the src vector to a block starting at @target_offset in the target
|
||
vector. The target vector will be resized and initialized with
|
||
default values as required.
|
||
|
||
If len goes beyond the length of the src vector the function will
|
||
fail hard.
|
||
*/
|
||
void @TYPE@_vector_memcpy_data_block( @TYPE@_vector_type * target , const @TYPE@_vector_type * src , int target_offset , int src_offset , int len) {
|
||
if ((src_offset + len) > src->size)
|
||
util_abort("%s: offset:%d blocksize:%d vector_size:%d - invalid \n",__func__ , src_offset , len , src->size);
|
||
|
||
/* Force a resize + default initialisation of the target. */
|
||
if (target->alloc_size < (target_offset + len))
|
||
@TYPE@_vector_iset( target , target_offset + len - 1 , target->default_value) ;
|
||
|
||
/* Copy the content. */
|
||
memcpy( &target->data[target_offset] , &src->data[src_offset] , len * sizeof * src->data );
|
||
|
||
/* Update size of target. */
|
||
if (target->size < (target_offset + len))
|
||
target->size = target_offset + len;
|
||
}
|
||
|
||
|
||
|
||
void @TYPE@_vector_memcpy_from_data( @TYPE@_vector_type * target , const @TYPE@ * src , int src_size ) {
|
||
@TYPE@_vector_reset( target );
|
||
//@TYPE@_vector_iset( target , src_size - 1 , 0 );
|
||
@TYPE@_vector_resize( target, src_size, 0);
|
||
memcpy( target->data , src , src_size * sizeof * target->data );
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_memcpy_data( @TYPE@ * target, const @TYPE@_vector_type * src ) {
|
||
memcpy( target , src->data , src->size * sizeof * src->data );
|
||
}
|
||
|
||
|
||
/**
|
||
This function will copy all the content (both header and data) from
|
||
the src vector to the target vector. If the the current allocation
|
||
size of the target vector is sufficiently large, it will not be
|
||
touched.
|
||
|
||
Observe that also the default value will be copied.
|
||
*/
|
||
|
||
|
||
void @TYPE@_vector_memcpy( @TYPE@_vector_type * target, const @TYPE@_vector_type * src ) {
|
||
@TYPE@_vector_reset( target );
|
||
target->default_value = src->default_value;
|
||
|
||
@TYPE@_vector_memcpy_data_block( target , src , 0 , 0 , src->size );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/**
|
||
Should essentially implement Python sliced index lookup.
|
||
*/
|
||
@TYPE@_vector_type * @TYPE@_vector_alloc_strided_copy( const @TYPE@_vector_type * src , int start , int stop , int stride ) {
|
||
@TYPE@_vector_type * copy = @TYPE@_vector_alloc( 0 , src->default_value );
|
||
if (start < 0)
|
||
start = src->size - start;
|
||
|
||
if (stop < 0)
|
||
stop = src->size - stop;
|
||
|
||
{
|
||
int src_index = start;
|
||
while (src_index < stop) {
|
||
@TYPE@_vector_append( copy , @TYPE@_vector_iget( src , src_index ));
|
||
src_index += stride;
|
||
}
|
||
}
|
||
return copy;
|
||
}
|
||
|
||
|
||
@TYPE@_vector_type * @TYPE@_vector_alloc_copy( const @TYPE@_vector_type * src) {
|
||
@TYPE@_vector_type * copy = @TYPE@_vector_alloc( src->size , src->default_value );
|
||
@TYPE@_vector_realloc_data__( copy , src->alloc_size, src->default_value );
|
||
copy->size = src->size;
|
||
memcpy(copy->data , src->data , src->alloc_size * sizeof * src->data );
|
||
return copy;
|
||
}
|
||
|
||
bool @TYPE@_vector_growable( const @TYPE@_vector_type * vector) {
|
||
return vector->data_owner;
|
||
}
|
||
|
||
|
||
@TYPE@ @TYPE@_vector_get_default(const @TYPE@_vector_type * vector) {
|
||
return vector->default_value;
|
||
}
|
||
|
||
|
||
/**
|
||
This will set the default value. This implies that everything
|
||
following the current length of the vector will be set to the new
|
||
default value, whereas values not explicitly set in the interior of
|
||
the vector will retain the old default value.
|
||
*/
|
||
|
||
|
||
void @TYPE@_vector_set_default(@TYPE@_vector_type * vector, @TYPE@ default_value) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
{
|
||
int i;
|
||
vector->default_value = default_value;
|
||
for (i=vector->size; i < vector->alloc_size; i++)
|
||
vector->data[i] = default_value;
|
||
}
|
||
}
|
||
|
||
/**
|
||
This function will append the value @default_value to the vector,
|
||
and then subsequently set this value as the new default.
|
||
*/
|
||
|
||
void @TYPE@_vector_append_default(@TYPE@_vector_type * vector , @TYPE@ default_value) {
|
||
@TYPE@_vector_append( vector , default_value );
|
||
@TYPE@_vector_set_default( vector , default_value );
|
||
}
|
||
|
||
|
||
/**
|
||
This function will iset the value @default_value into the vector,
|
||
and then subsequently set this value as the new default.
|
||
|
||
1. V = [1 , 2 , 3 , 4 ], default = 77
|
||
|
||
|
||
2. _iset_default(v , 10 , 66)
|
||
|
||
V = [1 ,2 , 3 , 4 , 77, 77, 77, 77, 77, 77, 66]
|
||
|
||
I.e. before setting the 66 value all values up to @index are
|
||
filled with the current default.
|
||
|
||
3. If @index is inside the current data region, there will be no
|
||
effect of the current default, i.e. _iset_default(v , 2 , 66)
|
||
will just give:
|
||
|
||
V = [1 ,2 , 66 , 4 ]
|
||
|
||
and 66 as the new default value.
|
||
*/
|
||
|
||
void @TYPE@_vector_iset_default(@TYPE@_vector_type * vector , int index , @TYPE@ default_value) {
|
||
@TYPE@_vector_iset( vector , index , default_value );
|
||
@TYPE@_vector_set_default( vector , default_value );
|
||
}
|
||
|
||
|
||
|
||
|
||
@TYPE@ @TYPE@_vector_iget(const @TYPE@_vector_type * vector , int index) {
|
||
@TYPE@_vector_assert_index(vector , index);
|
||
return vector->data[index];
|
||
}
|
||
|
||
/* Will start counting from the reverse end, as negative indexing in python:
|
||
|
||
vector_reverse_iget( v , -1 ) => The last element
|
||
vector_reverse_iget( v , -2 ) => The second to last element
|
||
|
||
*/
|
||
@TYPE@ @TYPE@_vector_reverse_iget(const @TYPE@_vector_type * vector , int index) {
|
||
return @TYPE@_vector_iget( vector , index + vector->size );
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
This might very well operate on a default value.
|
||
*/
|
||
void @TYPE@_vector_imul(@TYPE@_vector_type * vector, int index, @TYPE@ factor) {
|
||
@TYPE@_vector_assert_index(vector , index);
|
||
vector->data[index] *= factor;
|
||
}
|
||
|
||
|
||
/*****************************************************************/
|
||
/* Mathematical operations operating on the whole vector .*/
|
||
|
||
/* Vector * scalar */
|
||
void @TYPE@_vector_scale(@TYPE@_vector_type * vector, @TYPE@ factor) {
|
||
int i;
|
||
for (i=0; i < vector->size; i++)
|
||
vector->data[i] *= factor;
|
||
}
|
||
|
||
|
||
/* Vector / scalar; seperate _div function to ensure correct integer division. */
|
||
void @TYPE@_vector_div(@TYPE@_vector_type * vector, @TYPE@ divisor) {
|
||
int i;
|
||
for (i=0; i < vector->size; i++)
|
||
vector->data[i] /= divisor;
|
||
}
|
||
|
||
|
||
/* vector + scalar */
|
||
void @TYPE@_vector_shift(@TYPE@_vector_type * vector, @TYPE@ delta) {
|
||
int i;
|
||
for (i=0; i < vector->size; i++)
|
||
vector->data[i] += delta;
|
||
}
|
||
|
||
/* vector + vector */
|
||
void @TYPE@_vector_inplace_add( @TYPE@_vector_type * vector , const @TYPE@_vector_type * delta) {
|
||
if (vector->size != delta->size)
|
||
util_abort("%s: combining vectors with different size: %d and %d \n",__func__ , vector->size , delta->size);
|
||
{
|
||
int i;
|
||
for (i=0; i < vector->size; i++)
|
||
vector->data[i] += delta->data[i];
|
||
}
|
||
}
|
||
|
||
/* vector - vector */
|
||
void @TYPE@_vector_inplace_sub( @TYPE@_vector_type * vector , const @TYPE@_vector_type * delta) {
|
||
if (vector->size != delta->size)
|
||
util_abort("%s: combining vectors with different size: %d and %d \n",__func__ , vector->size , delta->size);
|
||
{
|
||
int i;
|
||
for (i=0; i < vector->size; i++)
|
||
vector->data[i] -= delta->data[i];
|
||
}
|
||
}
|
||
|
||
|
||
/* vector * vector (elementwise) */
|
||
void @TYPE@_vector_inplace_mul( @TYPE@_vector_type * vector , const @TYPE@_vector_type * factor) {
|
||
if (vector->size != factor->size)
|
||
util_abort("%s: combining vectors with different size: %d and %d \n",__func__ , vector->size , factor->size);
|
||
{
|
||
int i;
|
||
for (i=0; i < vector->size; i++)
|
||
vector->data[i] *= factor->data[i];
|
||
}
|
||
}
|
||
|
||
|
||
/* vector / vector (elementwise) */
|
||
void @TYPE@_vector_inplace_div( @TYPE@_vector_type * vector , const @TYPE@_vector_type * inv_factor) {
|
||
if (vector->size != inv_factor->size)
|
||
util_abort("%s: combining vectors with different size: %d and %d \n",__func__ , vector->size , inv_factor->size);
|
||
{
|
||
int i;
|
||
for (i=0; i < vector->size; i++)
|
||
vector->data[i] /= inv_factor->data[i];
|
||
}
|
||
}
|
||
|
||
/*****************************************************************/
|
||
|
||
|
||
|
||
|
||
/* Will return default value if index > size. Will fail HARD on negative indices (not that safe) ....*/
|
||
|
||
@TYPE@ @TYPE@_vector_safe_iget(const @TYPE@_vector_type * vector, int index) {
|
||
if (index >= vector->size)
|
||
return vector->default_value;
|
||
else {
|
||
if (index >= 0)
|
||
return vector->data[index];
|
||
else {
|
||
util_abort("%s: index:%d is invalid - only accepts positive indices.\n",__func__ , index);
|
||
return -1;
|
||
}
|
||
}
|
||
}
|
||
|
||
/** Will abort is size == 0 */
|
||
@TYPE@ @TYPE@_vector_get_last(const @TYPE@_vector_type * vector) {
|
||
return @TYPE@_vector_iget(vector , vector->size - 1);
|
||
}
|
||
|
||
|
||
/** Will abort is size == 0 */
|
||
@TYPE@ @TYPE@_vector_get_first(const @TYPE@_vector_type * vector) {
|
||
return @TYPE@_vector_iget(vector , 0);
|
||
}
|
||
|
||
/**
|
||
Observe that this function will grow the vector if necessary. If
|
||
index > size - i.e. leaving holes in the vector, these are
|
||
explicitly set to the default value. If a reallocation is needed it
|
||
is done in the realloc routine, otherwise it is done here.
|
||
*/
|
||
|
||
void @TYPE@_vector_iset(@TYPE@_vector_type * vector , int index , @TYPE@ value) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
{
|
||
if (index < 0)
|
||
util_abort("%s: Sorry - can NOT set negative indices. called with index:%d \n",__func__ , index);
|
||
{
|
||
if (vector->alloc_size <= index)
|
||
@TYPE@_vector_realloc_data__(vector , 2 * (index + 1), vector->default_value); /* Must have ( + 1) here to ensure we are not doing 2*0 */
|
||
vector->data[index] = value;
|
||
if (index >= vector->size) {
|
||
int i;
|
||
for (i=vector->size; i < index; i++)
|
||
vector->data[i] = vector->default_value;
|
||
vector->size = index + 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
The block_size can be negative, in which case the loop will walk to
|
||
the left in the vector.
|
||
*/
|
||
|
||
void @TYPE@_vector_iset_block(@TYPE@_vector_type * vector , int index , int block_size , @TYPE@ value) {
|
||
int sign = (block_size > 0) ? 1 : -1 ;
|
||
int c;
|
||
for (c=0; c < abs(block_size); c++)
|
||
@TYPE@_vector_iset( vector , index + c * sign , value);
|
||
}
|
||
|
||
|
||
/**
|
||
This function invokes _iset - i.e. growing the vector if needed. If
|
||
the index is not currently set, the default value will be used.
|
||
*/
|
||
|
||
@TYPE@ @TYPE@_vector_iadd( @TYPE@_vector_type * vector , int index , @TYPE@ delta) {
|
||
@TYPE@ new_value = @TYPE@_vector_safe_iget(vector , index ) + delta;
|
||
@TYPE@_vector_iset( vector , index , new_value );
|
||
return new_value;
|
||
}
|
||
|
||
/**
|
||
Will remove a block of length @block_size elements, starting at
|
||
@index from the vector. The @block_size might very well extend beyond
|
||
the length of the vector.
|
||
|
||
V = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9]
|
||
|
||
vector_idel_block( vector , 4 , 2 ) => V = [ 0 , 1 , 2 , 3 , 6 , 7 , 8 , 9]
|
||
|
||
The function is based on memmove() and probably not a high
|
||
performance player....
|
||
*/
|
||
|
||
|
||
void @TYPE@_vector_idel_block( @TYPE@_vector_type * vector , int index , int block_size) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
{
|
||
if ((index >= 0) && (index < vector->size) && (block_size >= 0)) {
|
||
if (index + block_size > vector->size)
|
||
block_size = vector->size - index;
|
||
|
||
index += block_size;
|
||
@TYPE@_vector_memmove( vector , index , -block_size );
|
||
} else
|
||
util_abort("%s: invalid input \n",__func__);
|
||
}
|
||
}
|
||
|
||
/**
|
||
Removes element @index from the vector, shifting all elements to
|
||
the right of @index one element to the left and shrinking the total
|
||
vector. The return value is the value which is removed.
|
||
*/
|
||
|
||
|
||
@TYPE@ @TYPE@_vector_idel( @TYPE@_vector_type * vector , int index) {
|
||
@TYPE@ del_value = @TYPE@_vector_iget( vector , index );
|
||
@TYPE@_vector_idel_block( vector , index , 1 );
|
||
return del_value;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
Removes all occurences of @value from the vector, thereby shrinking
|
||
the vector. The return value is the number of elements removed from
|
||
the vector.
|
||
*/
|
||
|
||
@TYPE@ @TYPE@_vector_del_value( @TYPE@_vector_type * vector , @TYPE@ del_value) {
|
||
int index = 0;
|
||
int del_count = 0;
|
||
while (true) {
|
||
if (index == vector->size)
|
||
break;
|
||
|
||
if (@TYPE@_vector_iget( vector , index) == del_value) {
|
||
@TYPE@_vector_idel( vector , index);
|
||
del_count++;
|
||
} else
|
||
index++;
|
||
}
|
||
return del_count;
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_insert( @TYPE@_vector_type * vector , int index , @TYPE@ value) {
|
||
if (index >= vector->size)
|
||
@TYPE@_vector_iset( vector , index , value );
|
||
else {
|
||
@TYPE@_vector_memmove( vector , index , 1 );
|
||
@TYPE@_vector_iset( vector , index , value );
|
||
}
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_append(@TYPE@_vector_type * vector , @TYPE@ value) {
|
||
//@TYPE@_vector_iset(vector , vector->size , value);
|
||
int size = vector->size;
|
||
@TYPE@_vector_resize(vector, size+1, 0);
|
||
vector->data[size] = value;
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_reset(@TYPE@_vector_type * vector) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
vector->size = 0;
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_free_container(@TYPE@_vector_type * vector) {
|
||
free( vector );
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_free_data(@TYPE@_vector_type * vector) {
|
||
@TYPE@_vector_reset(vector);
|
||
@TYPE@_vector_realloc_data__(vector , 0, vector->default_value);
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_free(@TYPE@_vector_type * vector) {
|
||
if (vector->data_owner)
|
||
free( vector->data );
|
||
@TYPE@_vector_free_container( vector );
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_free__(void * __vector) {
|
||
@TYPE@_vector_type * vector = (@TYPE@_vector_type *) __vector;
|
||
@TYPE@_vector_free( vector );
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_reset__(void * __vector) {
|
||
@TYPE@_vector_type * vector = @TYPE@_vector_safe_cast( __vector );
|
||
@TYPE@_vector_reset( vector );
|
||
}
|
||
|
||
|
||
int @TYPE@_vector_size(const @TYPE@_vector_type * vector) {
|
||
return vector->size;
|
||
}
|
||
|
||
|
||
/**
|
||
The pop function will remove the last element from the vector and
|
||
return it. If the vector is empty - it will abort.
|
||
*/
|
||
|
||
@TYPE@ @TYPE@_vector_pop(@TYPE@_vector_type * vector) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
{
|
||
if (vector->size > 0) {
|
||
@TYPE@ value = vector->data[vector->size - 1];
|
||
vector->size--;
|
||
return value;
|
||
} else {
|
||
util_abort("%s: trying to pop from empty vector \n",__func__);
|
||
return -1; /* Compiler shut up. */
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_rshift(@TYPE@_vector_type * vector , int shift) {
|
||
if (shift < 0)
|
||
@TYPE@_vector_memmove( vector , -shift , shift);
|
||
else {
|
||
int i;
|
||
@TYPE@_vector_memmove( vector , 0 , shift);
|
||
for (i=0; i < shift; i++)
|
||
vector->data[i] = vector->default_value;
|
||
}
|
||
}
|
||
|
||
void @TYPE@_vector_lshift(@TYPE@_vector_type * vector , int shift) {
|
||
@TYPE@_vector_rshift( vector , -shift);
|
||
}
|
||
|
||
|
||
@TYPE@ * @TYPE@_vector_get_ptr(const @TYPE@_vector_type * vector) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
return vector->data;
|
||
}
|
||
|
||
|
||
|
||
const @TYPE@ * @TYPE@_vector_get_const_ptr(const @TYPE@_vector_type * vector) {
|
||
return vector->data;
|
||
}
|
||
|
||
|
||
/**
|
||
Observe that there is a principle difference between the get_ptr()
|
||
functions and alloc_data_copy() when the vector has zero size. The
|
||
former functions will always return valid (@TYPE@ *) pointer,
|
||
altough possibly none of the elements have been set by the vector
|
||
instance, whereas the alloc_data_copy() function will return NULL
|
||
in that case.
|
||
*/
|
||
|
||
@TYPE@ * @TYPE@_vector_alloc_data_copy( const @TYPE@_vector_type * vector ) {
|
||
int size = vector->size * sizeof ( @TYPE@ );
|
||
@TYPE@ * copy = (@TYPE@*)util_calloc(vector->size , sizeof * copy );
|
||
if (copy != NULL)
|
||
memcpy( copy , vector->data , size);
|
||
return copy;
|
||
}
|
||
|
||
int @TYPE@_vector_element_size( const @TYPE@_vector_type * vector ) {
|
||
return sizeof( @TYPE@ );
|
||
}
|
||
|
||
void @TYPE@_vector_set_many(@TYPE@_vector_type * vector , int index , const @TYPE@ * data , int length) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
{
|
||
int min_size = index + length;
|
||
if (min_size > vector->alloc_size)
|
||
@TYPE@_vector_realloc_data__(vector , 2 * min_size, vector->default_value);
|
||
memcpy( &vector->data[index] , data , length * sizeof * data);
|
||
if (min_size > vector->size)
|
||
vector->size = min_size;
|
||
}
|
||
}
|
||
|
||
void @TYPE@_vector_set_all(@TYPE@_vector_type * vector , @TYPE@ value) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
{
|
||
int i;
|
||
for (i=0; i< vector->size; i++)
|
||
vector->data[i] = value;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
The bahviour of this function should closely follow the semantics
|
||
of the Python range() function.
|
||
*/
|
||
void @TYPE@_vector_init_range(@TYPE@_vector_type * vector , @TYPE@ value1 , @TYPE@ value2 , @TYPE@ delta) {
|
||
@TYPE@_vector_reset( vector );
|
||
if (delta != 0) {
|
||
bool valid_range = delta > 0 && value2 > value1;
|
||
#if @SIGNED_TYPE@
|
||
valid_range |= delta < 0 && value2 < value1;
|
||
#endif
|
||
|
||
if (valid_range) {
|
||
@TYPE@ current_value = value1;
|
||
while (true) {
|
||
@TYPE@_vector_append( vector , current_value );
|
||
current_value += delta;
|
||
|
||
if (delta > 0 && current_value >= value2)
|
||
break;
|
||
|
||
#if @SIGNED_TYPE@
|
||
if (delta < 0 && current_value <= value2)
|
||
break;
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
bool @TYPE@_vector_init_linear(@TYPE@_vector_type * vector , @TYPE@ start_value, @TYPE@ end_value, int num_values) {
|
||
if (num_values < 2)
|
||
return false;
|
||
|
||
@TYPE@_vector_reset( vector );
|
||
@TYPE@_vector_iset( vector, 0 , start_value);
|
||
{
|
||
double slope = (end_value - start_value) / (num_values - 1);
|
||
|
||
for (int i=1; i < num_values - 1; i++) {
|
||
@TYPE@ value = (@TYPE@) start_value + slope*i;
|
||
@TYPE@_vector_iset(vector, i, value);
|
||
}
|
||
}
|
||
@TYPE@_vector_iset( vector, num_values - 1, end_value);
|
||
return true;
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_append_many(@TYPE@_vector_type * vector , const @TYPE@ * data , int length) {
|
||
@TYPE@_vector_set_many( vector , @TYPE@_vector_size( vector ) , data , length);
|
||
}
|
||
|
||
void @TYPE@_vector_append_vector(@TYPE@_vector_type * vector , const @TYPE@_vector_type * other) {
|
||
@TYPE@_vector_append_many( vector , @TYPE@_vector_get_const_ptr( other ), @TYPE@_vector_size( other ));
|
||
}
|
||
|
||
|
||
/**
|
||
This will realloc the vector so that alloc_size exactly matches
|
||
size.
|
||
*/
|
||
|
||
void @TYPE@_vector_shrink(@TYPE@_vector_type * vector) {
|
||
@TYPE@_vector_realloc_data__(vector , vector->size, vector->default_value);
|
||
}
|
||
|
||
|
||
int @TYPE@_vector_get_max_index(const @TYPE@_vector_type * vector, bool reverse) {
|
||
if (vector->size == 0)
|
||
util_abort("%s: can not look for max_index in an empty vector \n",__func__);
|
||
{
|
||
int max_index;
|
||
int i;
|
||
if (reverse) {
|
||
@TYPE@ max_value;
|
||
max_index = vector->size - 1;
|
||
max_value = vector->data[max_index];
|
||
|
||
for (i=vector->size - 1; i >= 0; i--) {
|
||
if (vector->data[i] > max_value) {
|
||
max_value = vector->data[i];
|
||
max_index = i;
|
||
}
|
||
}
|
||
} else {
|
||
@TYPE@ max_value;
|
||
max_index = 0;
|
||
max_value = vector->data[max_index];
|
||
|
||
for (i=0; i < vector->size; i++) {
|
||
if (vector->data[i] > max_value) {
|
||
max_value = vector->data[i];
|
||
max_index = i;
|
||
}
|
||
}
|
||
}
|
||
return max_index;
|
||
}
|
||
}
|
||
|
||
|
||
@TYPE@ @TYPE@_vector_get_max(const @TYPE@_vector_type * vector) {
|
||
int max_index = @TYPE@_vector_get_max_index( vector , false );
|
||
return vector->data[ max_index ];
|
||
}
|
||
|
||
|
||
int @TYPE@_vector_get_min_index(const @TYPE@_vector_type * vector, bool reverse) {
|
||
if (vector->size == 0)
|
||
util_abort("%s: can not look for min_index in an empty vector \n",__func__);
|
||
{
|
||
int min_index;
|
||
int i;
|
||
if (reverse) {
|
||
@TYPE@ min_value;
|
||
min_index = vector->size - 1;
|
||
|
||
min_value = vector->data[min_index];
|
||
for (i=vector->size - 1; i >= 0; i--) {
|
||
if (vector->data[i] < min_value) {
|
||
min_value = vector->data[i];
|
||
min_index = i;
|
||
}
|
||
}
|
||
} else {
|
||
@TYPE@ min_value;
|
||
min_index = 0;
|
||
|
||
min_value = vector->data[min_index];
|
||
for (i=0; i < vector->size; i++) {
|
||
if (vector->data[i] < min_value) {
|
||
min_value = vector->data[i];
|
||
min_index = i;
|
||
}
|
||
}
|
||
}
|
||
return min_index;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
@TYPE@ @TYPE@_vector_get_min(const @TYPE@_vector_type * vector) {
|
||
int min_index = @TYPE@_vector_get_min_index( vector , false );
|
||
return vector->data[ min_index ];
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
@TYPE@ @TYPE@_vector_sum(const @TYPE@_vector_type * vector) {
|
||
int i;
|
||
@TYPE@ sum = 0;
|
||
for (i=0; i < vector->size; i++)
|
||
sum += vector->data[i];
|
||
return sum;
|
||
}
|
||
|
||
|
||
/**
|
||
Checks if the vector contains the value @value. The comparison is
|
||
done with ==; i.e. it is only suitable for integer-like types.
|
||
|
||
The implementation does a linear search through the vector and
|
||
returns the index of the @value, or -1 if @value is not found. If
|
||
the vector is known to be sorted you should use the
|
||
@TYPE@_vector_index_sorted() instead.
|
||
*/
|
||
|
||
int @TYPE@_vector_index(const @TYPE@_vector_type * vector , @TYPE@ value) {
|
||
if (vector->size) {
|
||
int index = 0;
|
||
while (true) {
|
||
if (vector->data[index] == value)
|
||
break;
|
||
|
||
index++;
|
||
if (index == vector->size) {
|
||
index = -1; /* Not found */
|
||
break;
|
||
}
|
||
}
|
||
|
||
return index;
|
||
} else
|
||
return -1;
|
||
}
|
||
|
||
bool @TYPE@_vector_contains(const @TYPE@_vector_type * vector , @TYPE@ value) {
|
||
if (@TYPE@_vector_index( vector , value) >= 0)
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
|
||
|
||
bool @TYPE@_vector_contains_sorted(const @TYPE@_vector_type * vector , @TYPE@ value) {
|
||
if (@TYPE@_vector_index_sorted( vector , value) >= 0)
|
||
return true;
|
||
else
|
||
return false;
|
||
}
|
||
|
||
|
||
/*
|
||
Should be reimplemented with util_sorted_contains_xxx().
|
||
*/
|
||
|
||
int @TYPE@_vector_index_sorted(const @TYPE@_vector_type * vector , @TYPE@ value) {
|
||
if (vector->size) {
|
||
|
||
if (value < vector->data[0])
|
||
return -1;
|
||
if (value == vector->data[ 0 ])
|
||
return 0;
|
||
|
||
{
|
||
int last_index = vector->size - 1;
|
||
if (value > vector->data[ last_index ])
|
||
return -1;
|
||
if (value == vector->data[ last_index])
|
||
return last_index;
|
||
}
|
||
|
||
|
||
{
|
||
int lower_index = 0;
|
||
int upper_index = vector->size - 1;
|
||
|
||
while (true) {
|
||
if ((upper_index - lower_index) <= 1)
|
||
/* Not found */
|
||
return -1;
|
||
|
||
{
|
||
int center_index = (lower_index + upper_index) / 2;
|
||
@TYPE@ center_value = vector->data[ center_index ];
|
||
|
||
if (center_value == value)
|
||
/* Found it */
|
||
return center_index;
|
||
else {
|
||
if (center_value > value)
|
||
upper_index = center_index;
|
||
else
|
||
lower_index = center_index;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} else
|
||
return -1;
|
||
}
|
||
|
||
/*****************************************************************/
|
||
/* Functions for sorting a vector instance. */
|
||
|
||
static int @TYPE@_vector_cmp(const void *_a, const void *_b) {
|
||
@TYPE@ a = *((@TYPE@ *) _a);
|
||
@TYPE@ b = *((@TYPE@ *) _b);
|
||
|
||
if (a > b)
|
||
return 1;
|
||
|
||
if (a < b)
|
||
return -1;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Reverse compare function. */
|
||
|
||
static int @TYPE@_vector_rcmp(const void *a, const void *b) {
|
||
return @TYPE@_vector_cmp( b , a );
|
||
}
|
||
|
||
|
||
/**
|
||
The input vector will be altered in place, so that the vector only
|
||
contains every numerical value __once__. On exit the values will be
|
||
sorted in increasing order.
|
||
|
||
vector = <7 , 0 , 1 , 7 , 1 , 0 , 7 , 1> => <0,1,7>
|
||
*/
|
||
|
||
void @TYPE@_vector_select_unique(@TYPE@_vector_type * vector) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
if (vector->size > 0) {
|
||
@TYPE@_vector_type * copy = @TYPE@_vector_alloc_copy( vector );
|
||
@TYPE@_vector_sort( copy );
|
||
@TYPE@_vector_reset( vector );
|
||
{
|
||
int i;
|
||
@TYPE@ previous_value = @TYPE@_vector_iget( copy , 0);
|
||
@TYPE@_vector_append( vector , previous_value);
|
||
|
||
for (i=1; i < copy->size; i++) {
|
||
@TYPE@ value = @TYPE@_vector_iget( copy , i );
|
||
if (value != previous_value)
|
||
@TYPE@_vector_append( vector , value);
|
||
previous_value = value;
|
||
}
|
||
}
|
||
@TYPE@_vector_free( copy );
|
||
}
|
||
}
|
||
|
||
/**
|
||
Inplace numerical sort of the vector; sorted in increasing order.
|
||
*/
|
||
void @TYPE@_vector_sort(@TYPE@_vector_type * vector) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
qsort(vector->data , vector->size , sizeof * vector->data , @TYPE@_vector_cmp);
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_rsort(@TYPE@_vector_type * vector) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
qsort(vector->data , vector->size , sizeof * vector->data , @TYPE@_vector_rcmp);
|
||
}
|
||
|
||
|
||
|
||
static int @TYPE@_vector_cmp_node(const void *_a, const void *_b) {
|
||
sort_node_type a = *((sort_node_type *) _a);
|
||
sort_node_type b = *((sort_node_type *) _b);
|
||
|
||
if (a.value < b.value)
|
||
return -1;
|
||
|
||
if (a.value > b.value)
|
||
return 1;
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
static int @TYPE@_vector_rcmp_node(const void *a, const void *b) {
|
||
return @TYPE@_vector_cmp_node( b , a );
|
||
}
|
||
|
||
/**
|
||
This function will allocate a (int *) pointer of indices,
|
||
corresponding to the permutations of the elements in the vector to
|
||
get it into sorted order. This permutation can then be used to sort
|
||
several vectors identically:
|
||
|
||
int_vector_type * v1;
|
||
bool_vector_type * v2;
|
||
double_vector_type * v2;
|
||
.....
|
||
.....
|
||
|
||
{
|
||
int * sort_perm = int_vector_alloc_sort_perm( v1 );
|
||
int_vector_permute( v1 , sort_perm );
|
||
bool_vector_permute( v2 , sort_perm );
|
||
double_vector_permute( v3 , sort_perm );
|
||
free(sort_perm);
|
||
}
|
||
|
||
*/
|
||
|
||
|
||
|
||
|
||
static perm_vector_type * @TYPE@_vector_alloc_sort_perm__(const @TYPE@_vector_type * vector, bool reverse) {
|
||
int * perm = (int*)util_calloc( vector->size , sizeof * perm ); // The perm_vector return value will take ownership of this array.
|
||
sort_node_type * sort_nodes = (sort_node_type*)util_calloc( vector->size , sizeof * sort_nodes );
|
||
int i;
|
||
for (i=0; i < vector->size; i++) {
|
||
sort_nodes[i].index = i;
|
||
sort_nodes[i].value = vector->data[i];
|
||
}
|
||
if (reverse)
|
||
qsort(sort_nodes , vector->size , sizeof * sort_nodes , @TYPE@_vector_rcmp_node);
|
||
else
|
||
qsort(sort_nodes , vector->size , sizeof * sort_nodes , @TYPE@_vector_cmp_node);
|
||
|
||
for (i=0; i < vector->size; i++)
|
||
perm[i] = sort_nodes[i].index;
|
||
|
||
free( sort_nodes );
|
||
return perm_vector_alloc( perm , vector->size );
|
||
}
|
||
|
||
|
||
perm_vector_type * @TYPE@_vector_alloc_sort_perm(const @TYPE@_vector_type * vector) {
|
||
return @TYPE@_vector_alloc_sort_perm__( vector , false );
|
||
}
|
||
|
||
|
||
perm_vector_type * @TYPE@_vector_alloc_rsort_perm(const @TYPE@_vector_type * vector) {
|
||
return @TYPE@_vector_alloc_sort_perm__( vector , true );
|
||
}
|
||
|
||
|
||
void @TYPE@_vector_permute(@TYPE@_vector_type * vector , const perm_vector_type * perm) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
{
|
||
int i;
|
||
@TYPE@ * tmp = (@TYPE@*)util_alloc_copy( vector->data , sizeof * tmp * vector->size );
|
||
for (i=0; i < vector->size; i++)
|
||
vector->data[i] = tmp[perm_vector_iget( perm , i )];
|
||
free( tmp );
|
||
}
|
||
}
|
||
|
||
/**
|
||
Looks through the vector and checks if it is in sorted form. If the
|
||
@reverse argument is true it will check for descending values,
|
||
otherwise for ascending values.
|
||
*/
|
||
|
||
bool @TYPE@_vector_is_sorted( const @TYPE@_vector_type * vector , bool reverse) {
|
||
bool sorted = true;
|
||
int start_index, delta,stop_index;
|
||
|
||
if (reverse) {
|
||
start_index = vector->size - 1;
|
||
stop_index = 0;
|
||
delta = -1;
|
||
} else {
|
||
start_index = 0;
|
||
stop_index = vector->size - 1;
|
||
delta = 1;
|
||
}
|
||
{
|
||
int index = start_index;
|
||
|
||
while (true) {
|
||
if (vector->data[index] > vector->data[index + delta]) {
|
||
sorted = false;
|
||
break;
|
||
}
|
||
index = index + delta;
|
||
if (index == stop_index)
|
||
break;
|
||
}
|
||
|
||
return sorted;
|
||
}
|
||
}
|
||
|
||
/*****************************************************************/
|
||
|
||
|
||
/**
|
||
This function can be used to implement lookup tables of various
|
||
types. The input vector @limits is supposed to contain container
|
||
limits, e.g.
|
||
|
||
limits = [0 , 1 , 2 , 3 , 4]
|
||
|
||
The @limits vector must be sorted. The function will then look up
|
||
in which bin @value fits and return the bin index. If the test
|
||
|
||
limit[i] <= value < limit[i+1]
|
||
|
||
succeeds the function will return i. If value is less than
|
||
limits[0] the function will return -1, if value is greater than
|
||
max( limit ) the function will return -1 * limit->size.
|
||
|
||
The parameter @guess can be used to speed up the process, a value
|
||
of @guess < 0 is interpreted as "no guess". When all input has been
|
||
validated the final search will be binary search.
|
||
*/
|
||
|
||
|
||
|
||
int @TYPE@_vector_lookup_bin( const @TYPE@_vector_type * limits , @TYPE@ value , int guess) {
|
||
if (value < limits->data[0])
|
||
return -1;
|
||
|
||
if (value > limits->data[ limits->size - 1])
|
||
return -1 * limits->size;
|
||
|
||
if (guess >= limits->size)
|
||
guess = -1; /* No guess */
|
||
|
||
return @TYPE@_vector_lookup_bin__( limits , value , guess );
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
This is the fast path and assumes that @value is within the limits,
|
||
and that guess < limits->size. See @TYPE@_vector_lookup_bin() for
|
||
further documentation.x
|
||
*/
|
||
|
||
int @TYPE@_vector_lookup_bin__( const @TYPE@_vector_type * limits , @TYPE@ value , int guess) {
|
||
if (guess >= 0) {
|
||
if ((limits->data[ guess ] <= value) && (limits->data[guess + 1] > value))
|
||
return guess; /* The guess was a hit. */
|
||
}
|
||
/* We did not have a guess - or it did not pay off. Start with a
|
||
binary search. */
|
||
{
|
||
int index;
|
||
int lower_index = 0;
|
||
int upper_index = limits->size - 1;
|
||
while (true) {
|
||
if ((upper_index - lower_index) == 1) {
|
||
/* We have found it. */
|
||
index = lower_index;
|
||
break;
|
||
}
|
||
|
||
{
|
||
int central_index = (lower_index + upper_index) / 2;
|
||
@TYPE@ central_value = limits->data[ central_index ];
|
||
|
||
if (central_value > value)
|
||
upper_index = central_index;
|
||
else
|
||
lower_index = central_index;
|
||
}
|
||
}
|
||
return index;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*****************************************************************/
|
||
|
||
|
||
void @TYPE@_vector_fprintf(const @TYPE@_vector_type * vector , FILE * stream , const char * name , const char * fmt) {
|
||
int i;
|
||
if (name != NULL)
|
||
fprintf(stream , "%s = [" , name);
|
||
else
|
||
fprintf(stream , "[");
|
||
|
||
for (i = 0; i < vector->size; i++) {
|
||
fprintf(stream , fmt , vector->data[i]);
|
||
if (i < (vector->size - 1))
|
||
fprintf(stream , ", ");
|
||
}
|
||
|
||
fprintf(stream , "]\n");
|
||
}
|
||
|
||
|
||
/*
|
||
This function does not consider the default value; it does a
|
||
vector_resize based on the input size.
|
||
*/
|
||
void @TYPE@_vector_fread_data( @TYPE@_vector_type * vector , int size, FILE * stream) {
|
||
@TYPE@_vector_realloc_data__( vector , size, vector->default_value );
|
||
util_fread( vector->data , sizeof * vector->data , size , stream , __func__);
|
||
vector->size = size;
|
||
}
|
||
|
||
|
||
|
||
void @TYPE@_vector_fwrite_data( const @TYPE@_vector_type * vector , FILE * stream ) {
|
||
util_fwrite( vector->data , sizeof * vector->data , vector->size , stream , __func__);
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
Writing:
|
||
1. Size
|
||
2. default value
|
||
3. Values
|
||
*/
|
||
|
||
void @TYPE@_vector_fwrite(const @TYPE@_vector_type * vector , FILE * stream) {
|
||
util_fwrite_int( vector->size , stream );
|
||
util_fwrite( &vector->default_value , sizeof vector->default_value , 1 , stream , __func__);
|
||
@TYPE@_vector_fwrite_data( vector , stream );
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
Observe that this function will reset the default value.
|
||
*/
|
||
void @TYPE@_vector_fread( @TYPE@_vector_type * vector , FILE * stream ) {
|
||
@TYPE@ default_value;
|
||
int size = util_fread_int( stream );
|
||
util_fread( &default_value , sizeof default_value , 1 , stream , __func__);
|
||
{
|
||
@TYPE@_vector_set_default( vector , default_value );
|
||
@TYPE@_vector_fread_data( vector , size , stream );
|
||
}
|
||
}
|
||
|
||
|
||
|
||
@TYPE@_vector_type * @TYPE@_vector_fread_alloc( FILE * stream ) {
|
||
@TYPE@_vector_type * vector = @TYPE@_vector_alloc( 0,0 );
|
||
@TYPE@_vector_fread( vector , stream );
|
||
return vector;
|
||
}
|
||
|
||
|
||
|
||
|
||
/*****************************************************************/
|
||
|
||
bool @TYPE@_vector_equal(const @TYPE@_vector_type * vector1 , const @TYPE@_vector_type * vector2) {
|
||
if (vector1->size == vector2->size) {
|
||
if (memcmp(vector1->data , vector2->data , sizeof * vector1->data * vector1->size) == 0)
|
||
return true;
|
||
else
|
||
return false;
|
||
} else
|
||
return false;
|
||
}
|
||
|
||
|
||
int @TYPE@_vector_first_equal(const @TYPE@_vector_type * vector1, const @TYPE@_vector_type * vector2, int offset) {
|
||
if (offset >= vector1->size)
|
||
return -2;
|
||
|
||
if (offset >= vector2->size)
|
||
return -2;
|
||
|
||
int index = offset;
|
||
while (vector1->data[index] != vector2->data[index]) {
|
||
index++;
|
||
|
||
if (index == vector1->size)
|
||
return -1;
|
||
|
||
if (index == vector2->size)
|
||
return -1;
|
||
}
|
||
|
||
return index;
|
||
}
|
||
|
||
|
||
|
||
int @TYPE@_vector_first_not_equal(const @TYPE@_vector_type * vector1, const @TYPE@_vector_type * vector2, int offset) {
|
||
if (offset >= vector1->size)
|
||
return -2;
|
||
|
||
if (offset >= vector2->size)
|
||
return -2;
|
||
|
||
int index = offset;
|
||
while (vector1->data[index] == vector2->data[index]) {
|
||
index++;
|
||
|
||
if (index == vector1->size)
|
||
return -1;
|
||
|
||
if (index == vector2->size)
|
||
return -1;
|
||
}
|
||
|
||
return index;
|
||
}
|
||
|
||
|
||
|
||
void @TYPE@_vector_apply(@TYPE@_vector_type * vector , @TYPE@_ftype * func) {
|
||
@TYPE@_vector_assert_writable( vector );
|
||
{
|
||
int i;
|
||
for (i=0; i < vector->size; i++)
|
||
vector->data[i] = func( vector->data[i] );
|
||
}
|
||
}
|
||
|
||
int @TYPE@_vector_count_equal( const @TYPE@_vector_type * vector , @TYPE@ cmp_value) {
|
||
int count = 0;
|
||
int i;
|
||
for (i=0; i < vector->size; i++)
|
||
if (vector->data[i] == cmp_value)
|
||
count += 1;
|
||
|
||
return count;
|
||
|
||
}
|
||
|
||
/*
|
||
The upper limit is inclusive - if it is commensurable with the
|
||
delta.
|
||
*/
|
||
|
||
void @TYPE@_vector_range_fill(@TYPE@_vector_type * vector , @TYPE@ limit1 , @TYPE@ delta , @TYPE@ limit2) {
|
||
@TYPE@ current_value = limit1;
|
||
|
||
if (delta == 0)
|
||
util_abort("%s: sorry can not have delta == 0 \n",__func__);
|
||
|
||
@TYPE@_vector_reset( vector );
|
||
while (true) {
|
||
@TYPE@_vector_append( vector , current_value );
|
||
current_value += delta;
|
||
if (delta > 0 && current_value > limit2)
|
||
break;
|
||
|
||
#if @SIGNED_TYPE@
|
||
if (delta < 0 && current_value < limit2)
|
||
break;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|