/* -*- mode: C -*- */ /* IGraph library. Copyright (C) 2005-2012 Gabor Csardi 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_attributes.h" #include "igraph_memory.h" #include "config.h" #include #include /* Should you ever want to have a thread-local attribute handler table, prepend * IGRAPH_THREAD_LOCAL to the following declaration */ igraph_attribute_table_t *igraph_i_attribute_table = 0; int igraph_i_attribute_init(igraph_t *graph, void *attr) { graph->attr = 0; if (igraph_i_attribute_table) { return igraph_i_attribute_table->init(graph, attr); } else { return 0; } } void igraph_i_attribute_destroy(igraph_t *graph) { if (igraph_i_attribute_table) { igraph_i_attribute_table->destroy(graph); } } int igraph_i_attribute_copy(igraph_t *to, const igraph_t *from, igraph_bool_t ga, igraph_bool_t va, igraph_bool_t ea) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->copy(to, from, ga, va, ea); } else { return 0; } } int igraph_i_attribute_add_vertices(igraph_t *graph, long int nv, void *attr) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->add_vertices(graph, nv, attr); } else { return 0; } } int igraph_i_attribute_permute_vertices(const igraph_t *graph, igraph_t *newgraph, const igraph_vector_t *idx) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->permute_vertices(graph, newgraph, idx); } else { return 0; } } int igraph_i_attribute_combine_vertices(const igraph_t *graph, igraph_t *newgraph, const igraph_vector_ptr_t *merges, const igraph_attribute_combination_t *comb) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->combine_vertices(graph, newgraph, merges, comb); } else { return 0; } } int igraph_i_attribute_add_edges(igraph_t *graph, const igraph_vector_t *edges, void *attr) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->add_edges(graph, edges, attr); } else { return 0; } } int igraph_i_attribute_permute_edges(const igraph_t *graph, igraph_t *newgraph, const igraph_vector_t *idx) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->permute_edges(graph, newgraph, idx); } else { return 0; } } int igraph_i_attribute_combine_edges(const igraph_t *graph, igraph_t *newgraph, const igraph_vector_ptr_t *merges, const igraph_attribute_combination_t *comb) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->combine_edges(graph, newgraph, merges, comb); } else { return 0; } } int igraph_i_attribute_get_info(const igraph_t *graph, igraph_strvector_t *gnames, igraph_vector_t *gtypes, igraph_strvector_t *vnames, igraph_vector_t *vtypes, igraph_strvector_t *enames, igraph_vector_t *etypes) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_info(graph, gnames, gtypes, vnames, vtypes, enames, etypes); } else { return 0; } } igraph_bool_t igraph_i_attribute_has_attr(const igraph_t *graph, igraph_attribute_elemtype_t type, const char *name) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->has_attr(graph, type, name); } else { return 0; } } int igraph_i_attribute_gettype(const igraph_t *graph, igraph_attribute_type_t *type, igraph_attribute_elemtype_t elemtype, const char *name) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->gettype(graph, type, elemtype, name); } else { return 0; } } int igraph_i_attribute_get_numeric_graph_attr(const igraph_t *graph, const char *name, igraph_vector_t *value) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_numeric_graph_attr(graph, name, value); } else { return 0; } } int igraph_i_attribute_get_numeric_vertex_attr(const igraph_t *graph, const char *name, igraph_vs_t vs, igraph_vector_t *value) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_numeric_vertex_attr(graph, name, vs, value); } else { return 0; } } int igraph_i_attribute_get_numeric_edge_attr(const igraph_t *graph, const char *name, igraph_es_t es, igraph_vector_t *value) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_numeric_edge_attr(graph, name, es, value); } else { return 0; } } int igraph_i_attribute_get_string_graph_attr(const igraph_t *graph, const char *name, igraph_strvector_t *value) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_string_graph_attr(graph, name, value); } else { return 0; } } int igraph_i_attribute_get_string_vertex_attr(const igraph_t *graph, const char *name, igraph_vs_t vs, igraph_strvector_t *value) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_string_vertex_attr(graph, name, vs, value); } else { return 0; } } int igraph_i_attribute_get_string_edge_attr(const igraph_t *graph, const char *name, igraph_es_t es, igraph_strvector_t *value) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_string_edge_attr(graph, name, es, value); } else { return 0; } } int igraph_i_attribute_get_bool_graph_attr(const igraph_t *graph, const char *name, igraph_vector_bool_t *value) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_bool_graph_attr(graph, name, value); } else { return 0; } } int igraph_i_attribute_get_bool_vertex_attr(const igraph_t *graph, const char *name, igraph_vs_t vs, igraph_vector_bool_t *value) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_bool_vertex_attr(graph, name, vs, value); } else { return 0; } } int igraph_i_attribute_get_bool_edge_attr(const igraph_t *graph, const char *name, igraph_es_t es, igraph_vector_bool_t *value) { if (igraph_i_attribute_table) { return igraph_i_attribute_table->get_bool_edge_attr(graph, name, es, value); } else { return 0; } } /** * \function igraph_i_set_attribute_table * \brief Attach an attribute table. * * This function attaches attribute handling code to the igraph library. * Note that the attribute handler table is \em not thread-local even if * igraph is compiled in thread-local mode. In the vast majority of cases, * this is not a significant restriction. * * \param table Pointer to an \ref igraph_attribute_table_t object * containing the functions for attribute manipulation. Supply \c * NULL here if you don't want attributes. * \return Pointer to the old attribute handling table. * * Time complexity: O(1). */ igraph_attribute_table_t * igraph_i_set_attribute_table(const igraph_attribute_table_t * table) { igraph_attribute_table_t *old = igraph_i_attribute_table; igraph_i_attribute_table = (igraph_attribute_table_t*) table; return old; } igraph_bool_t igraph_has_attribute_table() { return igraph_i_attribute_table != 0; } int igraph_attribute_combination_init(igraph_attribute_combination_t *comb) { IGRAPH_CHECK(igraph_vector_ptr_init(&comb->list, 0)); return 0; } void igraph_attribute_combination_destroy(igraph_attribute_combination_t *comb) { long int i, n = igraph_vector_ptr_size(&comb->list); for (i = 0; i < n; i++) { igraph_attribute_combination_record_t *rec = VECTOR(comb->list)[i]; if (rec->name) { igraph_Free(rec->name); } igraph_Free(rec); } igraph_vector_ptr_destroy(&comb->list); } int igraph_attribute_combination_add(igraph_attribute_combination_t *comb, const char *name, igraph_attribute_combination_type_t type, igraph_function_pointer_t func) { long int i, n = igraph_vector_ptr_size(&comb->list); /* Search, in case it is already there */ for (i = 0; i < n; i++) { igraph_attribute_combination_record_t *r = VECTOR(comb->list)[i]; const char *n = r->name; if ( (!name && !n) || (name && n && !strcmp(n, name)) ) { r->type = type; r->func = func; break; } } if (i == n) { /* This is a new attribute name */ igraph_attribute_combination_record_t *rec = igraph_Calloc(1, igraph_attribute_combination_record_t); if (!rec) { IGRAPH_ERROR("Cannot create attribute combination data", IGRAPH_ENOMEM); } if (!name) { rec->name = 0; } else { rec->name = strdup(name); } rec->type = type; rec->func = func; IGRAPH_CHECK(igraph_vector_ptr_push_back(&comb->list, rec)); } return 0; } int igraph_attribute_combination_remove(igraph_attribute_combination_t *comb, const char *name) { long int i, n = igraph_vector_ptr_size(&comb->list); /* Search, in case it is already there */ for (i = 0; i < n; i++) { igraph_attribute_combination_record_t *r = VECTOR(comb->list)[i]; const char *n = r->name; if ( (!name && !n) || (name && n && !strcmp(n, name)) ) { break; } } if (i != n) { igraph_attribute_combination_record_t *r = VECTOR(comb->list)[i]; if (r->name) { igraph_Free(r->name); } igraph_Free(r); igraph_vector_ptr_remove(&comb->list, i); } else { /* It is not there, we don't do anything */ } return 0; } int igraph_attribute_combination_query(const igraph_attribute_combination_t *comb, const char *name, igraph_attribute_combination_type_t *type, igraph_function_pointer_t *func) { long int i, def = -1, len = igraph_vector_ptr_size(&comb->list); for (i = 0; i < len; i++) { igraph_attribute_combination_record_t *rec = VECTOR(comb->list)[i]; const char *n = rec->name; if ( (!name && !n) || (name && n && !strcmp(n, name)) ) { *type = rec->type; *func = rec->func; return 0; } if (!n) { def = i; } } if (def == -1) { /* Did not find anything */ *type = IGRAPH_ATTRIBUTE_COMBINE_DEFAULT; *func = 0; } else { igraph_attribute_combination_record_t *rec = VECTOR(comb->list)[def]; *type = rec->type; *func = rec->func; } return 0; } int igraph_attribute_combination(igraph_attribute_combination_t *comb, ...) { va_list ap; IGRAPH_CHECK(igraph_attribute_combination_init(comb)); va_start(ap, comb); while (1) { igraph_function_pointer_t func = 0; igraph_attribute_combination_type_t type; const char *name; name = va_arg(ap, const char *); if (name == IGRAPH_NO_MORE_ATTRIBUTES) { break; } type = (igraph_attribute_combination_type_t)va_arg(ap, int); if (type == IGRAPH_ATTRIBUTE_COMBINE_FUNCTION) { #if defined(__GNUC__) func = va_arg(ap, void (*)(void)); #else func = va_arg(ap, void*); #endif } if (strlen(name) == 0) { name = 0; } IGRAPH_CHECK(igraph_attribute_combination_add(comb, name, type, func)); } va_end(ap); return 0; }