On 09.08.16 17.44, bitrex wrote:
> If I were implementing the entire printable ASCII character set it would
> be easy: just have array of values where each printable char input
> mapped directly one-to-one to a bitfield. But I'm only implementing a
> restricted subset of it, so if the values are all contiguous in a plain
> old array to facilitate quick lookup there would be quite a few
> unimplemented gaps taking up space. An array holding bitfields in say
> 0xFF hex format is also clunky for the user to modify.
>
> At the moment I just have a naive implementation where I have a std::map
> from a std::string to a pointer to an array of bools, stored in program
> memory, it works but it's not ideal, since std::map has a pretty huge
> memory footprint, and it seems goofy to store pointers in memory when
> the size of the data structure you're actually interested in is smaller
> than the width of a pointer type...
std::map uses red black trees. They are intended to keep iterators valid
on manipulations. Indeed they consume much memory.
=> Use a sorted vector with binary search.
But, the data type bool[] is bad too as it uses at least one byte per
entry.(Simply because common CPUs cannot handle sub byte addressing in a
way that complies with the rules for C++ pointers.)
=> use std::bitset instead. (It depends on the platform if bitset<7> can
be packed into a single byte. Some platforms require C++ objects to be
aligned at a machine size word.)
Furthermore ASCII has only 7 bits. I.e. you need at most 127 entries to
cover the entire ASCII range. So if you use a
std::array<std::bitset<7>,128> it will take 128 bytes. Really no big deal.
In contrast a sorted vector of pair<char,std::bitset<7>> will take twice
as much space when all entries are defined. So it is only efficient when
you have less than 64 symbols (likely with 7 segments). However the code
to do the binary search will probably take more than you saved.
The same applies to your initialization code since you did not use
constexpr. It will take much more memory than the resulting data
structures, including std::map.
Unfortunately std::bitset is out at this point since it does not support
reasonable constexpr list initializers. So you have to revert to
unsigned char, at least for the initialization.
Last but not least trivial solutions are sometimes quite effective:
switch (character)
{case 0:
return std::bitset<7>(0b1111110);
case 1:
return std::bitset<7>(0b0110000);
//...
}
Most compilers will create reasonably optimized code for this.
If you want to have even more compact solutions put only continuous runs
of values into arrays:
static const bitset<7> Numbers[10] =
{ 0b1111110,
0b0110000,
//...
};
static const bitset<7> Alpha[6] = // or [26]
{ 0b1110111,
//...
};
character -= '0';
if (character <= '9' - '0')
return Numbers[character];
character -= 'A' - '0';
if (character <= 'F' - 'A')
return Alpha[character];
return bitset<7>(0);
Marcel