/* Copyright Vladimir Prus 2004. Distributed under the Boost */ /* Software License, Version 1.0. (See accompanying */ /* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #include "../native.h" #include "../lists.h" #include "../strings.h" #include "../object.h" #include "../variable.h" /* Use quite klugy approach: when we add order dependency from 'a' to 'b', just append 'b' to of value of variable 'a'. */ LIST *add_pair( FRAME *frame, int flags ) { LIST* arg = lol_get( frame->args, 0 ); LISTITER iter = list_begin( arg ), end = list_end( arg ); var_set( frame->module, list_item( iter ), list_copy_range( arg, list_next( iter ), end ), VAR_APPEND ); return L0; } /** Given a list and a value, returns position of that value in the list, or -1 if not found. */ int list_index(LIST* list, OBJECT* value) { int result = 0; LISTITER iter = list_begin(list), end = list_end(list); for(; iter != end; iter = list_next(iter), ++result) { if (object_equal(list_item(iter), value)) return result; } return -1; } enum colors { white, gray, black }; /* Main routite of topological sort. Calls itself recursively on all adjacent vertices which were not yet visited. After that, 'current_vertex' is added to '*result_ptr'. */ void do_ts(int** graph, int current_vertex, int* colors, int** result_ptr) { int i; colors[current_vertex] = gray; for(i = 0; graph[current_vertex][i] != -1; ++i) { int adjacent_vertex = graph[current_vertex][i]; if (colors[adjacent_vertex] == white) do_ts(graph, adjacent_vertex, colors, result_ptr); /* The vertex is either black, in which case we don't have to do anything, a gray, in which case we have a loop. If we have a loop, it's not clear what useful diagnostic we can emit, so we emit nothing. */ } colors[current_vertex] = black; **result_ptr = current_vertex; (*result_ptr)++; } void topological_sort(int** graph, int num_vertices, int* result) { int i; int* colors = (int*)BJAM_CALLOC(num_vertices, sizeof(int)); for (i = 0; i < num_vertices; ++i) colors[i] = white; for(i = 0; i < num_vertices; ++i) if (colors[i] == white) do_ts(graph, i, colors, &result); BJAM_FREE(colors); } LIST *order( FRAME *frame, int flags ) { LIST* arg = lol_get( frame->args, 0 ); LIST* result = L0; int src; LISTITER iter = list_begin(arg), end = list_end(arg); /* We need to create a graph of order dependencies between the passed objects. We assume that there are no duplicates passed to 'add_pair'. */ int length = list_length(arg); int** graph = (int**)BJAM_CALLOC(length, sizeof(int*)); int* order = (int*)BJAM_MALLOC((length+1)*sizeof(int)); for(src = 0; iter != end; iter = list_next(iter), ++src) { /* For all object this one depend upon, add elements to 'graph' */ LIST* dependencies = var_get(frame->module, list_item(iter)); int index = 0; LISTITER dep_iter = list_begin(dependencies), dep_end = list_end(dependencies); graph[src] = (int*)BJAM_CALLOC(list_length(dependencies)+1, sizeof(int)); for(; dep_iter != dep_end; dep_iter = list_next(dep_iter)) { int dst = list_index(arg, list_item(dep_iter)); if (dst != -1) graph[src][index++] = dst; } graph[src][index] = -1; } topological_sort(graph, length, order); { int index = length-1; for(; index >= 0; --index) { int i; iter = list_begin(arg), end = list_end(arg); for (i = 0; i < order[index]; ++i, iter = list_next(iter)); result = list_push_back(result, object_copy(list_item(iter))); } } /* Clean up */ { int i; for(i = 0; i < length; ++i) BJAM_FREE(graph[i]); BJAM_FREE(graph); BJAM_FREE(order); } return result; } void init_order() { { const char* args[] = { "first", "second", 0 }; declare_native_rule("class@order", "add-pair", args, add_pair, 1); } { const char* args[] = { "objects", "*", 0 }; declare_native_rule("class@order", "order", args, order, 1); } }