3

I'm using bitset in my code:

std::bitset<MAX_INSTRUMENTS_NUMBER_IN_SYSTEM> updatedInstruments;

Often I need to iterate only values that "set" (or "not set"), this is how I do that:

for (int instrumentId = 0; instrumentId < MAX_INSTRUMENTS_NUMBER_IN_SYSTEM; instrumentId++) {
    if (!updatedInstruments[instrumentId]) {
        continue;
    }
    // work
}

Can this iteration be improved to be more readable and possibly faster?

Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305

1 Answers1

0

I don't think you can exploit the contiguity of set bits in your code using std::bitset: the interface doesn't provide anything to help in this task, and there's no legal way to access the underlying storage and work directly with it.1

If instead you can afford to change container, you can find several better alternatives. Here for example is a bitset-like structure that provides "enumerators" for active bits (it seems mostly like working with spans on images), and in the duplicate I linked above there are several other suggestions for data structures more specialized for this use case.


  1. Previously I supposed that iterators might have yielded some performance advantage, but turns out std::bitset doesn't have iterators :-o Also, a similar test performed on std::vector<bool> (which should pack bits more or less the same way) gave a ~2x slowdown using iterators both with g++ and clang++.
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • 1
    How do iterators gain performance? – Lightness Races in Orbit Apr 25 '14 at 10:49
  • I'm not saying it's guaranteed, but I can see some small optimization. Using an index requires re-calculation of the position in the underlying storage, bit shift and mask, while an iterator could cache, say, a word (that may go into a register) and just shift there until the next word is needed. I just pulled this out of my mind, but in general when dealing with containers where indexing is more complicated than pointer sum + dereference it's better to work with iterators, since they are optimized for traversal. – Matteo Italia Apr 25 '14 at 10:56
  • That makes sense in general but for a sequence container I'm not so sure. Can add vs inc really be noticeable here? – Lightness Races in Orbit Apr 25 '14 at 11:07
  • When I'm on a real computer I'll do some tests. OTOH, it's clear that here the real optimization (keeping the underlying data structure) would be to skip completely all-zero or all-set bytes (or even words) and in "mixed" bytes be able to do the shifts (to reach the "border" of each span) without all the clunky conversions to bool. This requires a container that either provides some support for a span-like interface, or exposes its internals a bit more. – Matteo Italia Apr 25 '14 at 11:23
  • @LightnessRacesinOrbit: I just tried to perform the benchmark but... jeez, `std::bitset` doesn't even have iterators! So I guess my point is completely moot... – Matteo Italia Apr 25 '14 at 13:44