Today, I tried to create a really simple sparse_array
container adapter. I did not provide all the STL-like functions, only the elementary ones as a proof of concept. I also trimmed the class from its copy constructor and all the unecessary things for this review actually. Here is the code:
#include <cstddef>
#include <map>
template<typename T, template <typename...> class Container=std::map>
struct sparse_array
{
class proxy
{
sparse_array& sp;
std::size_t index;
proxy(sparse_array& sp, std::size_t index):
sp(sp),
index(index)
{}
public:
proxy(const proxy& other) = default;
auto operator=(const proxy& other)
-> proxy&
{
sp.data[index] = T(other);
return *this;
}
auto operator=(const T& val)
-> proxy&
{
if (val != sp.default_value)
{
sp.data[index] = val;
}
else
{
sp.data.erase(index);
}
return *this;
}
operator T() const
{
auto res = sp.data.find(index);
if (res != sp.data.end())
{
return res->second;
}
return sp.default_value;
}
friend class sparse_array;
};
auto operator[](std::size_t index)
-> proxy
{
return { *this, index };
}
auto operator[](std::size_t index) const
-> const proxy
{
return { *this, index };
}
auto size() const
-> std::size_t
{
return data.size();
}
private:
T default_value = {};
Container<std::size_t, T> data;
};
What I tried to do is to have a sparse array whose number of elements is strictly equal to the number of elements that are different from default_value
, hence the elements that are deleted when default_value
is assigned to them. Here comes a small example:
#include <iostream>
int main()
{
sparse_array<int> sp;
std::cout << sp[15] << " / " << sp.size() << std::endl;
sp[8] = sp[13] = 9;
std::cout << sp[8] << " " << sp[13] << " / " << sp.size() << std::endl;
sp[11] = 0;
std::cout << sp[11] << " / " << sp.size() << std::endl;
sp[8] = 0;
std::cout << sp[8] << " / " << sp.size() << std::endl;
}
Do you think there are obvious design flaws in this code? I bet there are some in the proxy
mechanism, and it would be great if you could hilight some of them.