11/* Copyright 2004. Vladimir Prus
2+ * Copyright 2026 Paolo Pastori
23 * Distributed under the Boost Software License, Version 1.0.
34 * (See accompanying file LICENSE.txt or copy at
45 * https://www.bfgroup.xyz/b2/LICENSE.txt)
56 */
67
78#include " frames.h"
89#include " lists.h"
9- #include " mem.h"
1010#include " native.h"
1111#include " object.h"
12- #include " jam_strings.h"
1312#include " variable.h"
1413
14+ #include < utility>
15+ #include < vector>
1516
16- /* Use quite klugy approach: when we add order dependency from 'a' to 'b', just
17- * append 'b' to of value of variable 'a'.
17+
18+ // vertex type, NOTE: limit the max number of vertices in the graph
19+ using node_typ = uint16_t ;
20+ using node_vec = std::vector<node_typ>;
21+ using vec_graph = std::vector<node_vec>;
22+
23+ enum node_state { TO_VISIT , VISITING , VISITED };
24+ using state_vec = std::vector<char >;
25+
26+
27+ /* Use quite klugy approach: when we add order dependency from 'a' to 'b',
28+ * just append 'b' to of value of variable 'a'. NOTE: This is still here
29+ * only for backward compatibility reasons since latest order.jam use a
30+ * normal class method rule instead of this.
1831 */
1932LIST * add_pair ( FRAME * frame, int32_t flags )
2033{
@@ -30,7 +43,7 @@ LIST * add_pair( FRAME * frame, int32_t flags )
3043/* Given a list and a value, returns position of that value in the list, or -1
3144 * if not found.
3245 */
33- int32_t list_index ( LIST * list, OBJECT * value )
46+ static int32_t list_index ( LIST * list, OBJECT * value )
3447{
3548 int32_t result = 0 ;
3649 LISTITER iter = list_begin ( list );
@@ -41,114 +54,74 @@ int32_t list_index( LIST * list, OBJECT * value )
4154 return -1 ;
4255}
4356
44- enum colors { white, gray, black };
45-
46-
47- /* Main routine for topological sort. Calls itself recursively on all adjacent
48- * vertices which were not yet visited. After that, 'current_vertex' is added to
49- * '*result_ptr'.
57+ /* Routine for depth first traversal. Calls itself recursively on all adjacent
58+ * vertices which were not yet visited. After that, 'current_vertex' is added
59+ * to 'result'.
5060 */
51- void do_ts ( int32_t * * graph, int32_t current_vertex, int32_t * colors, int32_t * * result_ptr
52- )
61+ static void do_df ( FRAME * frame, const vec_graph & graph,
62+ int32_t current_vertex, state_vec & state, node_vec & result )
5363{
54- int32_t i;
55-
56- colors[ current_vertex ] = gray;
57- for ( i = 0 ; graph[ current_vertex ][ i ] != -1 ; ++i )
64+ state[ current_vertex ] = VISITING ;
65+ for ( auto adjacent_vertex : graph[ current_vertex ] )
5866 {
59- int32_t adjacent_vertex = graph[ current_vertex ][ i ];
60- if ( colors[ adjacent_vertex ] == white )
61- do_ts ( graph, adjacent_vertex, colors, result_ptr );
62- /* The vertex is either black, in which case we do not have to do
63- * anything, or gray, in which case we have a loop. If we have a loop,
64- * it is not clear what useful diagnostic we can emit, so we emit
65- * nothing.
66- */
67+ if ( state[ adjacent_vertex ] == TO_VISIT )
68+ do_df ( frame, graph, adjacent_vertex, state, result );
69+ // TODO
70+ // if ( state[ adjacent_vertex ] == VISITING )
71+ // emit warning "Cyclic order dependency on 'x' and 'y'."
6772 }
68- colors[ current_vertex ] = black;
69- **result_ptr = current_vertex;
70- ( *result_ptr )++;
73+ state[ current_vertex ] = VISITED ;
74+ result.push_back ( static_cast <node_typ>( current_vertex ) );
7175}
7276
73-
74- static void topological_sort ( int32_t * * graph, int32_t num_vertices, int32_t * result )
77+ static void topological_sort ( FRAME * frame, const vec_graph & graph,
78+ int32_t size, node_vec & result )
7579{
76- int32_t i;
77- int32_t * colors = ( int32_t * )BJAM_CALLOC ( num_vertices, sizeof ( int32_t ) );
78- for ( i = 0 ; i < num_vertices; ++i )
79- colors[ i ] = white;
80-
81- for ( i = num_vertices - 1 ; i >= 0 ; --i )
82- if ( colors[ i ] == white )
83- do_ts ( graph, i, colors, &result );
84-
85- BJAM_FREE ( colors );
80+ state_vec state (size, TO_VISIT );
81+ for ( int32_t i = size - 1 ; i >= 0 ; --i )
82+ if ( state[ i ] == TO_VISIT )
83+ do_df ( frame, graph, i, state, result );
8684}
8785
8886
8987LIST * order ( FRAME * frame, int32_t flags )
9088{
91- LIST * arg = lol_get ( frame->args , 0 );
92- LIST * result = L0 ;
93- int32_t src;
94- LISTITER iter = list_begin ( arg );
95- LISTITER const end = list_end ( arg );
96-
97- /* We need to create a graph of order dependencies between the passed
98- * objects. We assume there are no duplicates passed to 'add_pair'.
99- */
100- int32_t length = list_length ( arg );
101- int32_t * * graph = ( int32_t * * )BJAM_CALLOC ( length, sizeof ( int32_t * ) );
102- int32_t * order = ( int32_t * )BJAM_MALLOC ( ( length + 1 ) * sizeof ( int32_t ) );
103-
104- for ( src = 0 ; iter != end; iter = list_next ( iter ), ++src )
89+ b2::list_cref arg ( lol_get ( frame->args , 0 ) );
90+ int32_t length = arg.length ();
91+ if (length == 0 ) return L0 ;
92+
93+ // Build dependency graph
94+ vec_graph graph;
95+ graph.reserve ( length );
96+ for ( auto & obj : arg )
10597 {
106- /* For all objects this one depends upon, add elements to 'graph'. */
107- LIST * dependencies = var_get ( frame->module , list_item ( iter ) );
108- int32_t index = 0 ;
109- LISTITER dep_iter = list_begin ( dependencies );
110- LISTITER const dep_end = list_end ( dependencies );
111-
112- graph[ src ] = ( int32_t * )BJAM_CALLOC ( list_length ( dependencies ) + 1 ,
113- sizeof ( int32_t ) );
114- for ( ; dep_iter != dep_end; dep_iter = list_next ( dep_iter ) )
98+ b2::list_cref deps ( var_get ( frame->module , obj ) );
99+ node_vec depl;
100+ depl.reserve ( deps.length () );
101+ for ( auto & dep : deps )
115102 {
116- int32_t const dst = list_index ( arg, list_item ( dep_iter ) );
103+ int32_t dst = list_index ( * arg, dep );
117104 if ( dst != -1 )
118- graph[ src ][ index++ ] = dst ;
105+ depl. push_back ( static_cast <node_typ>( dst ) ) ;
119106 }
120- graph[ src ][ index ] = - 1 ;
107+ graph. push_back ( std::move ( depl ) ) ;
121108 }
122109
123- topological_sort ( graph, length, order );
110+ node_vec order;
111+ order.reserve ( length );
112+ topological_sort ( frame, graph, length, order );
124113
125- {
126- int32_t index = length - 1 ;
127- for ( ; index >= 0 ; --index )
128- {
129- int32_t i;
130- LISTITER iter = list_begin ( arg );
131- for ( i = 0 ; i < order[ index ]; ++i, iter = list_next ( iter ) );
132- result = list_push_back ( result, object_copy ( list_item ( iter ) ) );
133- }
134- }
114+ b2::list_ref result;
115+ for ( int32_t i = length - 1 ; i >= 0 ; --i )
116+ result.push_back ( object_copy ( arg[ order[ i ] ] ) );
135117
136- /* Clean up */
137- {
138- int32_t i;
139- for ( i = 0 ; i < length; ++i )
140- BJAM_FREE ( graph[ i ] );
141- BJAM_FREE ( graph );
142- BJAM_FREE ( order );
143- }
144-
145- return result;
118+ return result.release ();
146119}
147120
148121
149122void init_order ()
150123{
151- {
124+ { // for backward compatibility, see #593
152125 char const * args[] = { " first" , " second" , 0 };
153126 declare_native_rule ( " class@order" , " add-pair" , args, add_pair, 1 );
154127 }
0 commit comments