Exemplo n.º 1
0
int dfs_d(const igraph_t *graph, igraph_integer_t root,
	       igraph_neimode_t mode, igraph_bool_t unreachable, 
	       igraph_vector_t *order,
	       igraph_vector_t *order_out, igraph_vector_t *father,
	       igraph_vector_t *dist, igraph_dfshandler_t *in_callback,
	       igraph_dfshandler_t *out_callback,
	       void *extra) {
  
  long int no_of_nodes=igraph_vcount(graph);
  igraph_lazy_adjlist_t adjlist;
  igraph_stack_t stack;
  igraph_vector_char_t added;
  igraph_vector_long_t nptr;
  long int actroot;
  long int act_rank=0;
  long int rank_out=0;
  long int act_dist=0;

  if (root < 0 || root >= no_of_nodes) { 
    IGRAPH_ERROR("Invalid root vertex for DFS", IGRAPH_EINVAL);
  }

  if (mode != IGRAPH_OUT && mode != IGRAPH_IN && 
      mode != IGRAPH_ALL) {
    IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);
  }
  
  if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }

  IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_char_destroy, &added);
  IGRAPH_CHECK(igraph_stack_init(&stack, 100));
  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, mode, /*simplify=*/ 0));  
  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
  IGRAPH_CHECK(igraph_vector_long_init(&nptr, no_of_nodes));
  IGRAPH_FINALLY(igraph_vector_long_destroy, &nptr);

# define FREE_ALL() do { 			\
  igraph_vector_long_destroy(&nptr);            \
  igraph_lazy_adjlist_destroy(&adjlist);        \
  igraph_stack_destroy(&stack);                 \
  igraph_vector_char_destroy(&added);           \
  IGRAPH_FINALLY_CLEAN(4); } while (0)

  /* Resize result vectors and fill them with IGRAPH_NAN */
  
# define VINIT(v) if (v) {                      \
    igraph_vector_resize(v, no_of_nodes);       \
    igraph_vector_fill(v, IGRAPH_NAN); }
  
  VINIT(order);
  VINIT(order_out);
  VINIT(father);
  VINIT(dist);

# undef VINIT

  IGRAPH_CHECK(igraph_stack_push(&stack, root));
  VECTOR(added)[(long int)root] = 1;
  if (father) { VECTOR(*father)[(long int)root] = -1; }
  if (order) { VECTOR(*order)[act_rank++] = root; }
  if (dist) { VECTOR(*dist)[(long int)root] = 0; }
  if (in_callback) {
    igraph_bool_t terminate=in_callback(graph, root, 0, extra);
    if (terminate) { FREE_ALL(); return 0; }
  }

  for (actroot=0; actroot<no_of_nodes; actroot++) {

    /* 'root' first, then all other vertices */
    if (igraph_stack_empty(&stack)) {
      if (!unreachable) { break; }
      if (VECTOR(added)[actroot]) { continue; }
      IGRAPH_CHECK(igraph_stack_push(&stack, actroot));
      VECTOR(added)[actroot] = 1;
      if (father) { VECTOR(*father)[actroot] = -1; }
      if (order) { VECTOR(*order)[act_rank++] = actroot; }
      if (dist) { VECTOR(*dist)[actroot] = 0; }

      if (in_callback) {
	igraph_bool_t terminate=in_callback(graph, (igraph_integer_t) actroot,
					    0, extra);
	if (terminate) { FREE_ALL(); return 0; }
      }
    }
    
    while (!igraph_stack_empty(&stack)) {
      long int actvect=(long int) igraph_stack_top(&stack);
      igraph_vector_t *neis=igraph_lazy_adjlist_get(&adjlist, 
						    (igraph_integer_t) actvect);
      long int n=igraph_vector_size(neis);
      long int *ptr=igraph_vector_long_e_ptr(&nptr, actvect);

      igraph_vector_shuffle(neis);
      igraph_vector_print(neis);
      /* Search for a neighbor that was not yet visited */
      igraph_bool_t any=0;
      long int nei;
      while (!any && (*ptr) <n) {
	nei=(long int) VECTOR(*neis)[(*ptr)];
	any=!VECTOR(added)[nei];
	(*ptr) ++;
      }
      if (any) {
	/* There is such a neighbor, add it */
	IGRAPH_CHECK(igraph_stack_push(&stack, nei));
	VECTOR(added)[nei] = 1;
	if (father) { VECTOR(*father)[ nei ] = actvect; }
	if (order) { VECTOR(*order)[act_rank++] = nei; }
	act_dist++;
	if (dist) { VECTOR(*dist)[nei] = act_dist; }

	if (in_callback) {
	  igraph_bool_t terminate=in_callback(graph, (igraph_integer_t) nei,
					      (igraph_integer_t) act_dist, 
					      extra);
	  if (terminate) { FREE_ALL(); return 0; }
	}

      } else {
	/* There is no such neighbor, finished with the subtree */
	igraph_stack_pop(&stack);
	if (order_out) { VECTOR(*order_out)[rank_out++] = actvect; }
	act_dist--;

	if (out_callback) {
	  igraph_bool_t terminate=out_callback(graph, (igraph_integer_t) 
					       actvect, (igraph_integer_t) 
					       act_dist, extra);
	  if (terminate) { FREE_ALL(); return 0; }
	}
      }
    }      
  }

  FREE_ALL();
# undef FREE_ALL

  return 0;
}
Exemplo n.º 2
0
static gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, gchar** error) {
	enum { OUTSIDE, STARTING, NAME, ARGS } state = OUTSIDE;
	GString* out;
	GString* name = NULL;
	GString* arg = NULL;
	GPtrArray* args = NULL;
	gchar c;
	const gchar* r = text;
	gboolean changed = FALSE;

	if ( depth > 31) {
		if (error != NULL)
			*error = g_strdup("too much nesting in macros");
		return NULL;
	}

#define FGS(n) if (n) g_string_free(n,TRUE); n = NULL

#define FREE_ALL() \
	do { \
		FGS(name); \
		FGS(arg); \
		if (args) { \
			while(args->len) { void* p = g_ptr_array_remove_index_fast(args,0); if (p) g_free(p); } \
			g_ptr_array_free(args,TRUE); \
			args = NULL; \
		} \
	} while(0)

	if (error != NULL)
		*error = NULL;
	out = g_string_sized_new(64);

	while(1) {
		c = *r++;

		switch(state) {
			case OUTSIDE: {
				switch(c) {
					case '\0': {
						goto finish;
					} case '$': {
						state = STARTING;
						break;
					} default: {
						g_string_append_c(out,c);
						break;
					}
				}
				break;
			} case STARTING: {
				switch (c) {
					case '{': {
						args = g_ptr_array_new();
						arg = g_string_sized_new(32);
						name = g_string_sized_new(32);

						state = NAME;

						break;
					} case '\0': {
						g_string_append_c(out,'$');

						goto finish;
					} default: {
						g_string_append_c(out,'$');
						g_string_append_c(out,c);

						state = OUTSIDE;

						break;
					}
				}
				break;
			} case NAME: {
				if ( g_ascii_isalnum(c) || c == '_' || c == '-' || c == '.' ) {
					g_string_append_c(name,c);
				} else if ( c == ':') {
					state = ARGS;
				} else if ( c == '}') {
					gchar* resolved;

					g_ptr_array_add(args,NULL);

					resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
					if (resolved == NULL)
						goto on_error;

					changed = TRUE;

					g_string_append(out,resolved);
					wmem_free(NULL, resolved);

					FREE_ALL();

					state = OUTSIDE;
				} else if ( c == '\0') {
					if (error != NULL)
						*error = g_strdup("end of filter in the middle of a macro expression");
					goto on_error;
				} else {
					if (error != NULL)
						*error = g_strdup("invalid character in macro name");
					goto on_error;
				}
				break;
			} case ARGS: {
				switch(c) {
					case '\0': {
						if (error != NULL)
							*error = g_strdup("end of filter in the middle of a macro expression");
						goto on_error;
					} case ';': {
						g_ptr_array_add(args,g_string_free(arg,FALSE));

						arg = g_string_sized_new(32);
						break;
					} case '\\': {
						c = *r++;
						if (c) {
							g_string_append_c(arg,c);
							break;
						} else {
							if (error != NULL)
								*error = g_strdup("end of filter in the middle of a macro expression");
							goto on_error;
						}
					} default: {
						g_string_append_c(arg,c);
						break;
					} case '}': {
						gchar* resolved;
						g_ptr_array_add(args,g_string_free(arg,FALSE));
						g_ptr_array_add(args,NULL);

						arg = NULL;

						resolved = dfilter_macro_resolve(name->str, (gchar**)args->pdata, error);
						if (resolved == NULL)
							goto on_error;

						changed = TRUE;

						g_string_append(out,resolved);
						wmem_free(NULL, resolved);

						FREE_ALL();

						state = OUTSIDE;
						break;
					}
				}
				break;
			}
		}
	}

finish:
	{
		FREE_ALL();

		if (changed) {
			gchar* resolved = dfilter_macro_apply_recurse(out->str, depth + 1, error);
			g_string_free(out,TRUE);
			return resolved;
		} else {
			gchar* out_str = wmem_strdup(NULL, out->str);
			g_string_free(out,TRUE);
			return out_str;
		}
	}
on_error:
	{
		FREE_ALL();
		if (error != NULL) {
			if (*error == NULL)
				*error = g_strdup("unknown error in macro expression");
		}
		g_string_free(out,TRUE);
		return NULL;
	}
}