If I had a class that holds N number of equally sized vectors
. How would I go about implementing a standard iterator template that would iterate between 1 and N number of the vectors together. I wrote a small example demonstrating the problem.
#include <bitset>
#include <tuple>
#include <type_traits>
#include <vector>
//Since std::get<>() for types isn't in c++11, I use this meta-function to determine the index
//of a Type in a list of Types, starting from 0. ex: IndexOf<C, A, B, C>::value = 2
template <typename T, typename... Ts>
struct IndexOf;
template <typename T, typename... Ts>
struct IndexOf<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename U, typename... Ts>
struct IndexOf<T, U, Ts...> : std::integral_constant<std::size_t, 1 + IndexOf<T, Ts...>::value> {};
//Used to determine the slot we're interesting in.
using Handle = const std::size_t;
template<typename... Types>
class DataManager
{
static constexpr std::size_t TypeCount = sizeof... (Types);
using Flags = std::bitset<TypeCount>; //BitMask to determine if the handle has a certain piece of data initialized
std::size_t count, capacity;
std::tuple<std::vector<Types>..., std::vector<Flags>> vectors; //Tuple of vectors, holding the types and flags.
public:
DataManager(std::size_t n) : count(0), capacity(n),
vectors(std::make_tuple(std::vector<Types>(n)..., std::vector<Flags>(n)))
{}
template <typename Type, typename... Args>
void add(Handle handle, Args&&... args) { //Initializes the type in the handle slot of the vector
Flags& flags = std::get<TypeCount>(vectors)[handle]; //Flag the bit, notify that handle
flags.set(IndexOf<Type, Types...>::value); //has that piece of data initialized
std::get<IndexOf<Type, Types...>::value>(vectors)[handle] = Type{ args... };
}
template <typename Type>
Type& get(Handle handle) { //Returns the Type in handle slot of the vector
return std::get<IndexOf<Type, Types...>::value>(vectors)[handle];
}
template <typename Type>
bool has(Handle handle) { //Returns true if the Type is initialized, by checking the bitset
Flags& flags = std::get<TypeCount>(vectors)[handle];
return flags.test(IndexOf<Type, Types...>::value);
}
Handle push_back() {
return count++;
}
};
Which I currently use like this to access data:
//Simple Data
struct D0 { int x, y; };
struct D1 { float n, m; };
struct D2 { int x, y, z; };
int main()
{
DataManager<D0, D1, D2> manager(100);
Handle h0 = manager.push_back();
std::cout << manager.has<D0>(h0) << std::endl; //prints false, h0 doesn't have D0 initialized
manager.add<D0>(h0, 75, 20); //initialize D0 for h0
std::cout << manager.has<D0>(h0) << std::endl; //prints ture, h0 is now initialzed
std::cout << manager.get<D0>(h0).x << std::endl; //prints 75
}
How could I add iterator functionality to the DataManager class, that would only iterate over selected data like this?
int main()
{
...
for (D0 d1, D3 d3 : manager) {
... //Iterate over all D0s and D3s between 0 and count
}
//or
for(DataManager<D0>::iterator it = v.begin(); it != v.end(); ++it {
... //Iterate over just D0s between 0 and count - 10
}
}
Aucun commentaire:
Enregistrer un commentaire