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 |
|
---|
20 | namespace mi = ::boost::multi_index;
|
---|
21 |
|
---|
22 | #define UNINITIALIZED -1
|
---|
23 | #define CALCULATION_IN_PROGRESS -2
|
---|
24 |
|
---|
25 | struct 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 |
|
---|
38 | struct by_name {};
|
---|
39 | struct by_layer {};
|
---|
40 |
|
---|
41 | typedef 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 |
|
---|
49 | typedef node_deps_map_t::index<by_name >::type index_by_name_t;
|
---|
50 | typedef node_deps_map_t::index<by_layer>::type index_by_layer_t;
|
---|
51 |
|
---|
52 | node_deps_map_t deps_map;
|
---|
53 |
|
---|
54 | void 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 |
|
---|
71 | bool 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 |
|
---|
114 | void 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 |
|
---|
162 | int 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 | }
|
---|