Given, say, the following legacy list:
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 };
The node traits allow you to use the algos:
using algo = bi::circular_list_algorithms<legacy_node_traits>;
assert(algo::count(a) == 3);
assert(algo::count(b) == 3);
assert(algo::count(c) == 3);
And using value traits you can construct a list from the nodes. In your case the value traits can be trivially deduced from the node traits:
using List = bi::list<LIST_ENTRY,
bi::value_traits<
bi::trivial_value_traits<legacy_node_traits, bi::normal_link>
> >;
Now you could construct a NEW list and use it:
List l(std::begin(nodes), std::end(nodes)); // CAUTION, see below
for (auto& el : l) {
std::cout << el.value << "\n";
}
CAUTION: This has the side effect of reordering the list to the array order, losing the original link information.
It would be nice if there was a combination mid-way between bi::list::splice (which only operates on nodes already in another bi::list) and circular_list_algorithms::transfer (which assumes the opposite). Sadly, the obvious improvement here requires accessing the get_root_nod()
which is private.
The only way in which you can guarantee bi::list variants (such as the optional size tracking!) is to write a rather dumbish loop like:
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;
}
This is annoying in the sense that it seems to ask the compiler to emit code to establish all the same links again. It's not completely unrealistic to hope that a Very Smart Compiler might actually see through this and eliminate the no-op code?
Full Demo
Live On Coliru
#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;
}
Prints
-99
42
13
I've reversed the list beforehand to make doubly sure we didn't invent our own links. Also, l.check()
check all node/list invariants.