たとえば、次のレガシー リストがあるとします。
struct LIST_ENTRY {
LIST_ENTRY *Flink;
LIST_ENTRY *Blink;
int value;
};
LIST_ENTRY nodes[3] = {};
auto a = nodes+0;
auto b = nodes+1;
auto c = nodes+2;
*a = { b, c, 13 };
*b = { c, a, 42 };
*c = { a, b, -99 };
ノードの特性により、アルゴを使用できます。
using algo = bi::circular_list_algorithms<legacy_node_traits>;
assert(algo::count(a) == 3);
assert(algo::count(b) == 3);
assert(algo::count(c) == 3);
また、値特性を使用して、ノードからリストを作成できます。あなたの場合、値の特性はノードの特性から自明に推測できます。
using List = bi::list<LIST_ENTRY,
bi::value_traits<
bi::trivial_value_traits<legacy_node_traits, bi::normal_link>
> >;
これで、NEW リストを作成して使用できます。
List l(std::begin(nodes), std::end(nodes)); // CAUTION, see below
for (auto& el : l) {
std::cout << el.value << "\n";
}
注意: これには、リストを配列順に並べ替えるという副作用があり、元のリンク情報が失われます。
bi::list::splice (既に別の bi::list にあるノードでのみ動作) とcircular_list_algorithms::transfer (逆を想定) の中間に組み合わせがあると便利です。悲しいことに、ここでの明らかな改善にget_root_nod()
は、非公開の にアクセスする必要があります。
bi::list バリアント (オプションのサイズ トラッキングなど) を保証できる唯一の方法は、次のようなややばかげたループを記述することです。
List from_head(LIST_ENTRY* const head) {
List l;
auto it = head->Blink;
while (it != head) {
auto next = it->Blink;
l.push_front(*it); // intrusive, so modifies it->Blink!
it = next;
}
l.push_front(*head);
return l;
}
これは、すべて同じリンクを再度確立するためにコードを発行するようにコンパイラに要求しているように見えるという意味で厄介です。非常にスマートなコンパイラが実際にこれを見て、何もしないコードを排除することを期待するのは、完全に非現実的ではありませんか?
フルデモ
ライブ・オン・コリル
#include <boost/intrusive/trivial_value_traits.hpp>
#include <boost/intrusive/list.hpp>
#include <iostream>
namespace bi = boost::intrusive;
struct LIST_ENTRY {
LIST_ENTRY *Flink;
LIST_ENTRY *Blink;
int value;
};
struct legacy_node_traits
{
using node = LIST_ENTRY;
using node_ptr = node *;
using const_node_ptr = const node *;
static node *get_next(const node *n) { return n->Flink; }
static void set_next(node *n, node *next) { n->Flink = next; }
static node *get_previous(const node *n) { return n->Blink; }
static void set_previous(node *n, node *prev) { n->Blink = prev; }
};
using List = bi::list<LIST_ENTRY,
bi::value_traits<
bi::trivial_value_traits<legacy_node_traits, bi::normal_link>
> >;
List from_head(LIST_ENTRY* const head) {
List l;
auto it = head->Blink;
while (it != head) {
auto next = it->Blink;
l.push_front(*it); // intrusive, so modifies it->Blink!
it = next;
}
l.push_front(*head);
return l;
}
int main() {
LIST_ENTRY nodes[3] = {};
auto a = nodes+0;
auto b = nodes+1;
auto c = nodes+2;
*a = { b, c, 13 };
*b = { c, a, 42 };
*c = { a, b, -99 };
using algo = bi::circular_list_algorithms<legacy_node_traits>;
{
assert(algo::count(a) == 3);
assert(algo::count(b) == 3);
assert(algo::count(c) == 3);
algo::reverse(a);
}
List l = from_head(c);
l.check();
for (auto& el : l)
std::cout << el.value << std::endl;
}
版画
-99
42
13
独自のリンクを作成していないことを二重に確認するために、事前にリストを逆にしました. また、l.check()
すべてのノード/リストの不変条件を確認してください。