-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sizeof(variant) #19
Comments
Currently Plus there is the alignment issue: |
This may sound like heresy, as I changed my generator template to produce 4 types per recursion and lowered the depth to 500, which postponed the error to the definition of The smallest type suitable for holding template <typename K, typename... Constants>
struct integral_upper_bound
{
using type = void;
};
template <typename K, typename C, typename... Constants>
struct integral_upper_bound<K, C, Constants...>
{
using type = typename std::conditional<
K::value < C::value,
C,
typename integral_upper_bound<K, Constants...>::type
>::type;
};
template <typename... Types>
struct variant_traits
{
using invalid_index = typename integral_upper_bound<
std::integral_constant<std::size_t, sizeof...(Types)>,
std::integral_constant<std::uint8_t, UINT8_MAX>,
std::integral_constant<std::uint16_t, UINT16_MAX>,
std::integral_constant<std::uint32_t, UINT32_MAX>,
std::integral_constant<std::size_t, SIZE_MAX>
>::type;
using index_type = typename invalid_index::value_type;
static constexpr index_type invalid_value = invalid_index::value;
}; But then again, if you put that in a variant that contains something larger than |
I've found similar index-type shrinking in anthonyw's implementation, and a coarser one is optional in boost (BOOST_VARIANT_MINIMIZE_SIZE) |
I we are only thinking about the size of the index, I think we should just go with Using an What I don't know is whether this could impact runtime negatively. Modern processors like their 32bit or 64bit integers, so there might be a penalty when using an |
I think |
:+1 . My gut says space savings will be meaningful for our usecases while I really really doubt any negative runtime perf hit. |
This should be an easy change once we have a more complete set of tests. |
#include <iostream>
#include "variant.hpp"
#include <boost/variant.hpp>
struct big
{
double val[10]; // 8 * 10 = 80
};
i
int main()
{
{
std::cerr << sizeof(mapbox::util::variant<char>) << std::endl;
std::cerr << sizeof(mapbox::util::variant<char,int>) << std::endl;
std::cerr << sizeof(mapbox::util::variant<char,int,std::string>) << std::endl;
std::cerr << sizeof(mapbox::util::variant<char,int,std::string, big>) << std::endl;
}
{
std::cerr << sizeof(boost::variant<char>) << std::endl;
std::cerr << sizeof(boost::variant<char,int>) << std::endl;
std::cerr << sizeof(boost::variant<char,int,std::string>) << std::endl;
std::cerr << sizeof(boost::variant<char,int,std::string,big>) << std::endl;
}
return 0;
}
./test
16
16
32
88
8
8
32
88
88 From output above it looks like we could do a better job optimising for size when max size stored is sizeof(T) < 16. But this is not a typical use case. |
planning to take a look at using |
For the record OSRM just hit this and moved away from using a mapbox/variant internally saving > 11 GB. |
…f + use `unsigned int` by default. This addresses `sizeof` discrepancies between boost/std/mapbox variants (ref #19)
#include <iostream>
#include <mapbox/variant.hpp>
#include <boost/variant.hpp>
#include <variant>
struct big
{
double val[10]; // 8 * 10 = 80
};
int main()
{
{
std::cerr << "mapbox::variant" << std::endl;
std::cerr << sizeof(mapbox::util::variant<char>) << std::endl;
std::cerr << sizeof(mapbox::util::variant<char,int>) << std::endl;
std::cerr << sizeof(mapbox::util::variant<char,int,std::string>) << std::endl;
std::cerr << sizeof(mapbox::util::variant<char,int,std::string, big>) << std::endl;
}
{
std::cerr << "boost::variant" << std::endl;
std::cerr << sizeof(boost::variant<char>) << std::endl;
std::cerr << sizeof(boost::variant<char,int>) << std::endl;
std::cerr << sizeof(boost::variant<char,int,std::string>) << std::endl;
std::cerr << sizeof(boost::variant<char,int,std::string,big>) << std::endl;
}
{
std::cerr << "std::variant" << std::endl;
std::cerr << sizeof(std::variant<char>) << std::endl;
std::cerr << sizeof(std::variant<char,int>) << std::endl;
std::cerr << sizeof(std::variant<char,int,std::string>) << std::endl;
std::cerr << sizeof(std::variant<char,int,std::string,big>) << std::endl;
}
return 0;
}
|
My understanding is that calling
sizeof
on a variant should produce the size of the largest type the variant includes. And my assumption is thatsizeof
for a given type is not going to be consistent/portable across arches and platforms. However, as we should strive to have the variant use at little memory as possible I wanted to surface this ticket for discussion.Dumb questions that I assume the answer is
duh, no
, but want to know for sure:sizeof(variant_instance)
by adapting to howsizeof(std::string)
and other types might be different per platform? Might catch regressions if we ever made a mistake that increased the variant memory footprint.The text was updated successfully, but these errors were encountered: