Motivation: Have std::vector<std::unique_ptr<T>>
accessibility at std::vector<T>
speed.
std::vector
have one inconvenience - you can't store pointers nor indexes to elements if the vector grows/alters.
To overcome this problem we usually use vector of pointers / deque (if only grow) / list / etc. Having our elements in heap have significant overhead on creation, traverse, and per element access.
To store "pointer" (or key) to element in vector I have back array of indices.
Condensed version:
struct Key{
int index; // index of key_indices
};
struct Element {
int key_index; // never changes
Value value;
};
std::vector<Element> data; // usual continious vector, no magic here
std::vector<int> key_indices; // point to data[]. these values changes when erase/insert to data
std::vector<int> free_indices;
void emplace_back(){
// if have no free_indices
data.emplace_back();
key_indices.emplace_back(data.size() - 1);
data.back().key_index = key_indices.size() - 1;
}
Key get_key(std::vector<Element>::iterator iter){
return {iter->key_index};
}
Value& operator[](Key key){
return data[key_indices[key.index]].value;
}
Value& operator[](int index){
return data[index].value;
}
void erase(std::vector<Element>::iterator iter){
free_indices.push_back(iter->key_index);
update_indices(iter + 1, data.end(), -1);
data.erase(iter);
}
// same with insert, emplace_front, etc.
template<class iter>
void update_indices(iter from, iter to, int shift) {
for (auto it = from; it != to; ++it)
{
key_indices[it->key_index] += shift;
}
}
And used like:
KeyContainer<Data> list;
list.emplace_back().back().x = 100;
list.emplace_back().back().x = 200;
auto key = list.get_key(list.end()-1);
list.erase(list.begin()); // all indices invalidated
std::cout << list[key].x << std::endl; // key still valid
In other words Key - is array index that always points to the same element, just like pointer to std::vector<std::unique_ptr<T>>
element.
It is approximately 6-10 times faster than std::vector<std::unique_ptr<T>>
/list
on creation, 3-4 times faster than deque(at least with VS2015/clang). Same speed as vector when traverse/index access. And approx 10% slower with key access. I tried to use pointers instead of indices, but didn't see a difference.
Is there some ready library solution for container like this (vector with indices back-array (or ptr back-array))?