Home > Blockchain >  Simpler, portable way to iterate over all char values?
Simpler, portable way to iterate over all char values?

Time:03-12

For a class I'm teaching I needed to write a piece of code to iterate over all possible char values. I wanted to do this in a way that was portable across different C implementations. This meant that

  • I can't assume char is signed or unsigned,
  • I can't assume char is eight bits,
  • I can't assume that sizeof(int) > 1,
  • I can't assume the int32_t etc. types exist,
  • I can't assume that integer overflow will not trap,
  • etc.

The best solution I came up with was the following unusual do ... while loop:

char ch = numeric_limits<char>::min();
process(ch);
do {
    ch  ;
    process(ch);
} while (ch != numeric_limits<char>::max());

This approach works, but it feels pretty clunky to me. It intuitively makes sense that an approach like this might be needed because the number of increments is one more than the number of possible characters, but perhaps there's a fundamentally different approach available that more closely resembles a traditional for loop.

Is there a portable way to achieve this that's less clunky than this?

CodePudding user response:

but perhaps there's a fundamentally different approach available that more closely resembles a traditional for loop.

Well, you can use an actual for loop:

#include <limits>
#include <iostream>

void process(char ch)
{
  std::cout << static_cast<long>(ch) << ' ';
}

int main()
{
  for ( char ch = std::numeric_limits<char>::min(); ;   ch )
  {
    process(ch);
    if ( ch == std::numeric_limits<char>::max() )
      break;
  }
  std::cout << '\n';
}

CodePudding user response:

You can create a wrapper class that looks like a container.

struct Chars {

    enum {
        Chars_MIN = std::numeric_limits<char>::min(),
        Chars_MAX = std::numeric_limits<char>::max()
    };

    struct Iterator {
        char c_;
        bool end_;

        Iterator (char c, bool e = false) : c_(c), end_(e) {}

        auto & operator    () {
            if (c_ == Chars_MAX) end_ = true;
            else   c_;
            return *this;
        }

        auto operator * () const { return c_; }

        auto operator == (const Iterator &other) const {
            return c_ == other.c_ && end_ == other.end_;
        }

        auto operator != (const Iterator &other) const {
            return !(*this == other);
        }
    };

    Iterator begin () const { return Iterator(Chars_MIN); }
    Iterator end () const { return Iterator(Chars_MAX, true); }
};

Then, you can use the modern for syntax:

    Chars ccc;
    for (auto x : ccc) {
        process(x);
    }
  • Related