Repository navigation
Expand file tree
/
Copy pathmod_order.cpp
More file actions
133 lines (113 loc) · 3.9 KB
/
Copy pathmod_order.cpp
File metadata and controls
133 lines (113 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* Copyright 2004. Vladimir Prus
* Copyright 2026 Paolo Pastori
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE.txt or copy at
* https://www.bfgroup.xyz/b2/LICENSE.txt)
*/
#include "frames.h"
#include "lists.h"
#include "native.h"
#include "object.h"
#include "variable.h"
#include <utility>
#include <vector>
// vertex type, NOTE: limit the max number of vertices in the graph
using node_typ = uint16_t;
using node_vec = std::vector<node_typ>;
using vec_graph = std::vector<node_vec>;
enum node_state { TO_VISIT, VISITING, VISITED };
using state_vec = std::vector<char>;
/* Use quite klugy approach: when we add order dependency from 'a' to 'b',
* just append 'b' to of value of variable 'a'. NOTE: This is still here
* only for backward compatibility reasons since latest order.jam use a
* normal class method rule instead of this.
*/
LIST * add_pair( FRAME * frame, int32_t flags )
{
LIST * arg = lol_get( frame->args, 0 );
LISTITER iter = list_begin( arg );
LISTITER const 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.
*/
static int32_t list_index( LIST * list, OBJECT * value )
{
int32_t result = 0;
LISTITER iter = list_begin( list );
LISTITER const end = list_end( list );
for ( ; iter != end; iter = list_next( iter ), ++result )
if ( object_equal( list_item( iter ), value ) )
return result;
return -1;
}
/* Routine for depth first traversal. Calls itself recursively on all adjacent
* vertices which were not yet visited. After that, 'current_vertex' is added
* to 'result'.
*/
static void do_df( FRAME * frame, const vec_graph & graph,
int32_t current_vertex, state_vec & state, node_vec & result )
{
state[ current_vertex ] = VISITING;
for ( auto adjacent_vertex : graph[ current_vertex ] )
{
if ( state[ adjacent_vertex ] == TO_VISIT )
do_df( frame, graph, adjacent_vertex, state, result );
// TODO
//if ( state[ adjacent_vertex ] == VISITING )
// emit warning "Cyclic order dependency on 'x' and 'y'."
}
state[ current_vertex ] = VISITED;
result.push_back( static_cast<node_typ>( current_vertex ) );
}
static void topological_sort( FRAME * frame, const vec_graph & graph,
int32_t size, node_vec & result )
{
state_vec state(size, TO_VISIT);
for ( int32_t i = size - 1; i >= 0; --i )
if ( state[ i ] == TO_VISIT )
do_df( frame, graph, i, state, result );
}
LIST * order( FRAME * frame, int32_t flags )
{
b2::list_cref arg( lol_get( frame->args, 0 ) );
int32_t length = arg.length();
if (length == 0) return L0;
// Build dependency graph
vec_graph graph;
graph.reserve( length );
for ( auto & obj : arg )
{
b2::list_cref deps( var_get( frame->module, obj ) );
node_vec depl;
depl.reserve( deps.length() );
for ( auto & dep : deps )
{
int32_t dst = list_index( *arg, dep );
if ( dst != -1 )
depl.push_back( static_cast<node_typ>( dst ) ) ;
}
graph.push_back( std::move( depl ) );
}
node_vec order;
order.reserve( length );
topological_sort( frame, graph, length, order );
b2::list_ref result;
for ( int32_t i = length - 1; i >= 0; --i )
result.push_back( object_copy( arg[ order[ i ] ] ) );
return result.release();
}
void init_order()
{
{ // for backward compatibility, see #593
char const * args[] = { "first", "second", 0 };
declare_native_rule( "class@order", "add-pair", args, add_pair, 1 );
}
{
char const * args[] = { "objects", "*", 0 };
declare_native_rule( "class@order", "order", args, order, 1 );
}
}