https://github.com/igraph/xdata-igraph
Tip revision: 06b86098e79ef0ddb286ede16c46254e57017eb1 authored by Gabor Csardi on 10 December 2014, 18:06:01 UTC
Update xdata README, to not merge into main igraph
Update xdata README, to not merge into main igraph
Tip revision: 06b8609
igraph_set.c
/* -*- mode: C -*- */
/*
IGraph library.
Copyright (C) 2006-2012 Gabor Csardi <csardi.gabor@gmail.com>
334 Harvard street, Cambridge, MA 02139 USA
This program 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 2 of the License, or
(at your option) any later version.
This program 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 for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "igraph_types.h"
#include "igraph_memory.h"
#include "igraph_error.h"
#include "igraph_types_internal.h"
#include "config.h"
#include <assert.h>
#include <string.h> /* memmove */
#define SET(s) ((s).stor_begin)
/**
* \ingroup set
* \function igraph_set_init
* \brief Initializes a set.
*
* \param set pointer to the set to be initialized
* \param size the expected number of elements in the set
*
* \return error code:
* \c IGRAPH_ENOMEM if there is not enough memory.
*
* Time complexity: operating system dependent, should be around
* O(n), n is the expected size of the set.
*/
int igraph_set_init(igraph_set_t *set, int long size) {
long int alloc_size = size > 0 ? size : 1;
if (size < 0) { size = 0; }
set->stor_begin=igraph_Calloc(alloc_size, igraph_integer_t);
set->stor_end=set->stor_begin + alloc_size;
set->end=set->stor_begin;
return 0;
}
/**
* \ingroup set
* \function igraph_set_destroy
* \brief Destroys a set object.
*
* \param set pointer to the set to be destroyed
*
* Time complexity: operating system dependent.
*/
void igraph_set_destroy(igraph_set_t* set) {
assert(set != 0);
if (set->stor_begin != 0) {
igraph_Free(set->stor_begin);
set->stor_begin = NULL;
}
}
/**
* \ingroup set
* \function igraph_set_inited
* \brief Determines whether a set is initialized or not.
*
* This function checks whether the internal storage for the members of the
* set has been allocated or not, and it assumes that the pointer for the
* internal storage area contains \c NULL if the area is not initialized yet.
* This only applies if you have allocated an array of sets with \c igraph_Calloc or
* if you used the \c IGRAPH_SET_NULL constant to initialize the set.
*
* \param set The set object.
*
* Time complexity: O(1)
*/
igraph_bool_t igraph_set_inited(igraph_set_t* set) {
return (set->stor_begin != 0);
}
/**
* \ingroup set
* \function igraph_set_reserve
* \brief Reserve memory for a set.
*
* \param set The set object.
* \param size the new \em allocated size of the set.
*
* Time complexity: operating system dependent, should be around
* O(n), n is the new allocated size of the set.
*/
int igraph_set_reserve(igraph_set_t* set, long int size) {
long int actual_size = igraph_set_size(set);
igraph_integer_t *tmp;
assert(set != NULL);
assert(set->stor_begin != NULL);
if (size <= actual_size) return 0;
tmp=igraph_Realloc(set->stor_begin, (size_t) size, igraph_integer_t);
if (tmp==0) {
IGRAPH_ERROR("cannot reserve space for set", IGRAPH_ENOMEM);
}
set->stor_begin=tmp;
set->stor_end=set->stor_begin+size;
set->end=set->stor_begin+actual_size;
return 0;
}
/**
* \ingroup set
* \function igraph_set_empty
* \brief Decides whether the size of the set is zero.
*
* \param set The set object.
* \return Non-zero number if the size of the set is not zero and
* zero otherwise.
*
* Time complexity: O(1).
*/
igraph_bool_t igraph_set_empty(const igraph_set_t* set) {
assert(set != NULL);
assert(set->stor_begin != NULL);
return set->stor_begin == set->end;
}
/**
* \ingroup set
* \function igraph_set_clear
* \brief Removes all elements from a set.
*
* </para><para>
* This function simply sets the size of the set to zero, it does
* not free any allocated memory. For that you have to call
* \ref igraph_set_destroy().
* \param v The set object.
*
* Time complexity: O(1).
*/
void igraph_set_clear(igraph_set_t* set) {
assert(set != NULL);
assert(set->stor_begin != NULL);
set->end = set->stor_begin;
}
/**
* \ingroup set
* \function igraph_vector_set
* \brief Gives the size (=length) of the set.
*
* \param v The set object
* \return The size of the set.
*
* Time complexity: O(1).
*/
long int igraph_set_size(const igraph_set_t* set) {
assert(set != NULL);
assert(set->stor_begin != NULL);
return set->end-set->stor_begin;
}
/**
* \ingroup set
* \function igraph_set_add
* \brief Adds an element to the set.
*
* \param set The set object.
* \param e The element to be added.
* \return Error code:
* \c IGRAPH_ENOMEM: not enough memory.
*
* Time complexity: O(log(n)), n is the number of elements in \p set.
*/
int igraph_set_add(igraph_set_t* set, igraph_integer_t e) {
long int left, right, middle;
long int size;
assert(set != NULL);
assert(set->stor_begin != NULL);
size = igraph_set_size(set);
/* search where to insert the new element */
left = 0;
right = size-1;
while (left < right-1) {
middle = (left+right)/2;
if (SET(*set)[middle] > e) {
right = middle;
} else if (SET(*set)[middle] < e) {
left = middle;
} else {
left = middle;
break;
}
}
if (right >= 0 && SET(*set)[left] != e && SET(*set)[right] == e) {
left = right;
}
while (left < size && set->stor_begin[left] < e) left++;
if (left >= size || set->stor_begin[left] != e) {
/* full, allocate more storage */
if (set->stor_end == set->end) {
long int new_size = size * 2;
if (new_size == 0) new_size = 1;
IGRAPH_CHECK(igraph_set_reserve(set, new_size));
}
/* Element should be inserted at position 'left' */
if (left < size)
memmove(set->stor_begin+left+1, set->stor_begin+left,
(size_t) (size-left)*sizeof(set->stor_begin[0]));
set->stor_begin[left] = e;
set->end += 1;
}
return 0;
}
/**
* \ingroup set
* \function igraph_set_contains
* \brief Checks whether a given element is in the set or not.
*
* \param set The set object.
* \param e The element being sought.
* \return Positive integer (true) if \p e is found, zero (false) otherwise.
*
* Time complexity: O(log(n)), n is the number of elements in \p set.
*/
int igraph_set_contains(igraph_set_t* set, igraph_integer_t e) {
long int left, right, middle;
assert(set != NULL);
assert(set->stor_begin != NULL);
left = 0;
right = igraph_set_size(set)-1;
/* search for the new element */
while (left < right-1) {
middle = (left+right)/2;
if (SET(*set)[middle] > e) {
right = middle;
} else if (SET(*set)[middle] < e) {
left = middle;
} else {
left = middle;
return 1;
}
}
if (SET(*set)[left] != e && SET(*set)[right] == e) return 1;
return (SET(*set)[left] == e);
}
/**
* \ingroup set
* \function igraph_set_iterate
* \brief Iterates through the element to the set.
*
* Elements are returned in an arbitrary order.
*
* \param set The set object.
* \param state Internal state of the iteration.
* This should be a pointer to a \c long variable
* which must be zero for the first invocation.
* The object should not be adjusted and its value should
* not be used for anything during the iteration.
* \param element The next element or \c NULL (if the iteration
* has ended) is returned here.
*
* \return Nonzero if there are more elements, zero otherwise.
*/
igraph_bool_t igraph_set_iterate(igraph_set_t* set, long int* state,
igraph_integer_t* element) {
assert(set != 0);
assert(set->stor_begin != 0);
assert(state != 0);
assert(element != 0);
if (*state < igraph_set_size(set)) {
*element = set->stor_begin[*state];
*state = *state+1;
return 1;
} else {
*element = 0;
return 0;
}
}