1 | /* Copyright Vladimir Prus 2004. Distributed under the Boost */ |
---|
2 | /* Software License, Version 1.0. (See accompanying */ |
---|
3 | /* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ |
---|
4 | |
---|
5 | #include "../native.h" |
---|
6 | #include "../lists.h" |
---|
7 | #include "../strings.h" |
---|
8 | #include "../newstr.h" |
---|
9 | #include "../variable.h" |
---|
10 | #include "../debug.h" |
---|
11 | |
---|
12 | |
---|
13 | /* Use quite klugy approach: when we add order dependency from 'a' to 'b', |
---|
14 | just append 'b' to of value of variable 'a'. |
---|
15 | */ |
---|
16 | LIST *add_pair( PARSE *parse, FRAME *frame ) |
---|
17 | { |
---|
18 | LIST* arg = lol_get( frame->args, 0 ); |
---|
19 | |
---|
20 | var_set(arg->string, list_copy(0, arg->next), VAR_APPEND); |
---|
21 | |
---|
22 | return L0; |
---|
23 | } |
---|
24 | |
---|
25 | /** Given a list and a value, returns position of that value in |
---|
26 | the list, or -1 if not found. |
---|
27 | */ |
---|
28 | int list_index(LIST* list, const char* value) |
---|
29 | { |
---|
30 | int result = 0; |
---|
31 | for(; list; list = list->next, ++result) { |
---|
32 | if (strcmp(list->string, value) == 0) |
---|
33 | return result; |
---|
34 | } |
---|
35 | return -1; |
---|
36 | } |
---|
37 | |
---|
38 | enum colors { white, gray, black }; |
---|
39 | |
---|
40 | /* Main routite of topological sort. Calls itself recursively on all |
---|
41 | adjacent vertices which were not yet visited. After that, 'current_vertex' |
---|
42 | is added to '*result_ptr'. |
---|
43 | */ |
---|
44 | void do_ts(int** graph, int current_vertex, int* colors, int** result_ptr) |
---|
45 | { |
---|
46 | int i; |
---|
47 | |
---|
48 | colors[current_vertex] = gray; |
---|
49 | for(i = 0; graph[current_vertex][i] != -1; ++i) { |
---|
50 | int adjacent_vertex = graph[current_vertex][i]; |
---|
51 | |
---|
52 | if (colors[adjacent_vertex] == white) |
---|
53 | do_ts(graph, adjacent_vertex, colors, result_ptr); |
---|
54 | else if (colors[adjacent_vertex] == gray) |
---|
55 | ; /* This is loop. Not sure what to do... */ |
---|
56 | } |
---|
57 | colors[current_vertex] = black; |
---|
58 | **result_ptr = current_vertex; |
---|
59 | (*result_ptr)++; |
---|
60 | } |
---|
61 | |
---|
62 | void topological_sort(int** graph, int num_vertices, int* result) |
---|
63 | { |
---|
64 | int i; |
---|
65 | int* colors = (int*)calloc(num_vertices, sizeof(int)); |
---|
66 | if ( DEBUG_PROFILE ) |
---|
67 | profile_memory( num_vertices*sizeof(int) ); |
---|
68 | for (i = 0; i < num_vertices; ++i) |
---|
69 | colors[i] = white; |
---|
70 | |
---|
71 | for(i = 0; i < num_vertices; ++i) |
---|
72 | if (colors[i] == white) |
---|
73 | do_ts(graph, i, colors, &result); |
---|
74 | |
---|
75 | free(colors); |
---|
76 | } |
---|
77 | |
---|
78 | LIST *order( PARSE *parse, FRAME *frame ) |
---|
79 | { |
---|
80 | LIST* arg = lol_get( frame->args, 0 ); |
---|
81 | LIST* tmp; |
---|
82 | LIST* result = 0; |
---|
83 | int src, dst; |
---|
84 | |
---|
85 | /* We need to create a graph of order dependencies between |
---|
86 | the passed objects. We assume that there are no duplicates |
---|
87 | passed to 'add_pair'. |
---|
88 | */ |
---|
89 | int length = list_length(arg); |
---|
90 | int** graph = (int**)calloc(length, sizeof(int*)); |
---|
91 | int* order = (int*)malloc((length+1)*sizeof(int)); |
---|
92 | if ( DEBUG_PROFILE ) |
---|
93 | profile_memory( length*sizeof(int*) + (length+1)*sizeof(int) ); |
---|
94 | |
---|
95 | for(tmp = arg, src = 0; tmp; tmp = tmp->next, ++src) { |
---|
96 | /* For all object this one depend upon, add elements |
---|
97 | to 'graph' */ |
---|
98 | LIST* dependencies = var_get(tmp->string); |
---|
99 | int index = 0; |
---|
100 | |
---|
101 | graph[src] = (int*)calloc(list_length(dependencies)+1, sizeof(int)); |
---|
102 | if ( DEBUG_PROFILE ) |
---|
103 | profile_memory( (list_length(dependencies)+1)*sizeof(int) ); |
---|
104 | for(; dependencies; dependencies = dependencies->next) { |
---|
105 | int dst = list_index(arg, dependencies->string); |
---|
106 | if (dst != -1) |
---|
107 | graph[src][index++] = dst; |
---|
108 | } |
---|
109 | graph[src][index] = -1; |
---|
110 | } |
---|
111 | |
---|
112 | topological_sort(graph, length, order); |
---|
113 | |
---|
114 | { |
---|
115 | int index = length-1; |
---|
116 | for(; index >= 0; --index) { |
---|
117 | int i; |
---|
118 | tmp = arg; |
---|
119 | for (i = 0; i < order[index]; ++i, tmp = tmp->next); |
---|
120 | result = list_new(result, tmp->string); |
---|
121 | } |
---|
122 | } |
---|
123 | |
---|
124 | /* Clean up */ |
---|
125 | { |
---|
126 | int i; |
---|
127 | for(i = 0; i < length; ++i) |
---|
128 | free(graph[i]); |
---|
129 | free(graph); |
---|
130 | free(order); |
---|
131 | } |
---|
132 | |
---|
133 | return result; |
---|
134 | } |
---|
135 | |
---|
136 | void init_order() |
---|
137 | { |
---|
138 | { |
---|
139 | char* args[] = { "first", "second", 0 }; |
---|
140 | declare_native_rule("class@order", "add-pair", args, add_pair, 1); |
---|
141 | } |
---|
142 | |
---|
143 | { |
---|
144 | char* args[] = { "objects", "*", 0 }; |
---|
145 | declare_native_rule("class@order", "order", args, order, 1); |
---|
146 | } |
---|
147 | |
---|
148 | |
---|
149 | } |
---|