Ticket #11801: DirectedGraph.cpp

File DirectedGraph.cpp, 5.7 KB (added by Valentyn Shtronda <valiko.ua@…>, 7 years ago)
Line 
1// Please use attached simplified file to reproduce the problem.
2// I used boost 1.59 with VS2015.
3// Reproduced in all 4 configurations (debug/release, x86/x64).
4// I'm not sure if it's a bug or limitation of multi_index, but commenting any line in fill_test_date() fixes the problem, so seems like a bug in some specific conditions.
5// If it's multi_index limitation, please mention this in description of modify/modify_key.
6//
7// The problem:
8// multi_index container has two keys ordered_unique and ordered_non_unique.
9// In calc_layer() I call modify() on first index and change the key of second index.
10// During calculation of new key for second index, other recursive calls to modify() may be performed.
11// All calls to modify() return true but in some cases second index is not correctly ordered in we see message "WRONG SORT ORDER BY LAYER".
12
13#include <set>
14#include <string>
15#include <boost/algorithm/string.hpp>
16#include <boost/multi_index_container.hpp>
17#include <boost/multi_index/member.hpp>
18#include <boost/multi_index/ordered_index.hpp>
19
20namespace mi = ::boost::multi_index;
21
22#define UNINITIALIZED -1
23#define CALCULATION_IN_PROGRESS -2
24
25struct node_info_t
26{
27 node_info_t(const std::string& name)
28 : name(name)
29 , layer(UNINITIALIZED)
30 {
31 }
32
33 std::string name;
34 std::set<std::string> deps;
35 int layer;
36};
37
38struct by_name {};
39struct by_layer {};
40
41typedef mi::multi_index_container<
42 node_info_t,
43 mi::indexed_by<
44 mi::ordered_unique <mi::tag<by_name >, mi::member<node_info_t, std::string, &node_info_t::name> >,
45 mi::ordered_non_unique<mi::tag<by_layer>, mi::member<node_info_t, int, &node_info_t::layer> >
46 >
47> node_deps_map_t;
48
49typedef node_deps_map_t::index<by_name >::type index_by_name_t;
50typedef node_deps_map_t::index<by_layer>::type index_by_layer_t;
51
52node_deps_map_t deps_map;
53
54void add_node(const char* node_name, const char* node_deps_string)
55{
56 auto res = deps_map.emplace(node_name);
57 if (!res.second)
58 {
59 printf("Already inserted.\n");
60 }
61 else if (*node_deps_string)
62 {
63 deps_map.modify(res.first,
64 [=](node_info_t& node_info)
65 {
66 boost::split(node_info.deps, node_deps_string, boost::is_any_of(" "), boost::algorithm::token_compress_on);
67 });
68 }
69}
70
71bool calc_layer(index_by_name_t::iterator it)
72{
73 if (it->layer == CALCULATION_IN_PROGRESS)
74 return printf("Circular reference.\n"), false;
75 if (it->layer != UNINITIALIZED)
76 return true;
77
78 bool succeeded = deps_map.modify(it,
79 [=](node_info_t& node_info)
80 {
81 if (node_info.deps.size() == 0)
82 {
83 node_info.layer = 0;
84 }
85 else
86 {
87 index_by_name_t& index_by_name = deps_map.get<by_name>();
88 node_info.layer = CALCULATION_IN_PROGRESS;
89 for (const std::string& dep_name : node_info.deps)
90 {
91 index_by_name_t::iterator dep_it = index_by_name.find(dep_name);
92 if (dep_it == deps_map.end())
93 {
94 node_info.layer = UNINITIALIZED;
95 printf("Unknown dependency.\n");
96 return;
97 }
98 if (!calc_layer(dep_it))
99 {
100 node_info.layer = UNINITIALIZED;
101 return;
102 }
103 node_info.layer = std::max(node_info.layer, dep_it->layer + 1);
104 }
105 }
106 });
107
108 if (!succeeded)
109 return printf("modify() failed.\n"), false;
110
111 return it->layer >= 0;
112}
113
114void fill_test_data()
115{
116 add_node("m1", "");
117 add_node("b1", "");
118 add_node("o1", "");
119 add_node("a3", "");
120 add_node("t1", "");
121 add_node("m2", "");
122 add_node("c1", "b1");
123 add_node("r1", "b1");
124 add_node("t2", "b1");
125 add_node("o2", "b1");
126 add_node("h1", "b1");
127 add_node("h2", "b1");
128 add_node("d1", "b1");
129 add_node("x1", "b1");
130 add_node("h3", "b1");
131 add_node("m3", "b1");
132 add_node("l1", "b1 c1");
133 add_node("w1", "b1 c1");
134 add_node("g1", "b1 t2");
135 add_node("s1", "b1 r1");
136 add_node("s2", "b1 r1 t2 l1 d1 o2 m1");
137 add_node("a6", "b1 s2");
138 add_node("m4", "b1 s2 o2");
139 add_node("a4", "b1 s2 o2 l1");
140 add_node("w2", "b1 s2 c1 w1");
141 add_node("s3", "b1 s2 o2 h2");
142 add_node("s4", "b1 s2 o2 h2 t2");
143 add_node("a5", "b1 s2 d1 r1 w1");
144 add_node("g2", "b1 s2 r1 c1 l1");
145 add_node("b2", "b1 s2 r1 d1 a5");
146 add_node("s5", "b1 s2 r1");
147 add_node("w3", "b1 x1");
148 add_node("m5", "b1 s2");
149 add_node("m6", "b1 s2 o2 m4");
150 add_node("m7", "b1 s2");
151 add_node("n1", "b1 s2 l1");
152 add_node("p1", "b1 s2 l1 x1");
153 add_node("s6", "b1 s2 l1 g1 t2");
154 add_node("c2", "b1 s2 o2 m4");
155 add_node("c3", "b1 s2 l1 o2 w1 m5");
156 add_node("c4", "b1 s2 l1 g1 t2");
157 add_node("d2", "b1 s2 l1 o2");
158 add_node("a1", "b1 s2 t2 g1 a4 a6 t1 m2 a3 d1 s1 o1 a5 b2 w1 l1");
159 add_node("a2", "b1 s2 t2 g1 a4 a6 t1 m2 r1 a3 d1 b2 s3 s4 o2 s1 o1 a5 w1 l1 c1");
160}
161
162int main(int, char*[])
163{
164 fill_test_data();
165
166 for (auto it = deps_map.begin(); it != deps_map.end(); ++it)
167 {
168 calc_layer(it);
169 }
170
171 index_by_layer_t& index_by_layer = deps_map.get<by_layer>();
172 if (!std::is_sorted(index_by_layer.begin(), index_by_layer.end(),
173 [](const node_info_t& l, const node_info_t& r) { return l.layer < r.layer; }))
174 printf("\nWRONG SORT ORDER BY LAYER\n");
175
176 return 0;
177}