Friday, February 26, 2010

Smashing The Stack : What is a neat way of breaking out of many for loops at once?

A Problem that has been posted and reposted on StackOverflow boils down to "What is a neat way of breaking out of many for loops at once?" An ugly solution looks like this:
Context context;
bool flag = false;

for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
for (int k = 0; k < 100; k++) {
  updateContext(i,j,k,context);   if ( shouldBreak( context, i,j,k) ) {
    flag = true;
    break;
  }
}
if (flag) break;
}
if (flag) break;
}
Here we've wrapped all other data that is changing into a context object that is updated every iteration, and is tested against. So how can we make this "neat" .. here's one kind of solution.
void loopfn(Context & context)
{
  for (int i = 0; i < 100; i++) {
  for (int j = 0; j < 100; j++) {
  for (int k = 0; k < 100; k++) {
  updateContext(i,j,k,context);
  if ( shouldBreak( context, i,j,k) ) return;
  }
  }
  }
}
};

Context context;
loopfn(context);
One further step that can be helpful in further refactoring is:
class Looper
{
  Looper(Context & c) : context(c) {}
  Context context;
  bool shouldBreak(int i,int k,int k);
  void updateContext(int i,int k,int k);
  void loop()
  {
    for (int i = 0; i < 100; i++) {
    for (int j = 0; j < 100; j++) {
    for (int k = 0; k < 100; k++) {
    updateContext();
    if ( shouldBreak(i,j,k) ) return;
    }
    }
    }
  }
};

Context context;
Looper l(context);
l.loop();
IMHO this is easier to maintain than the original loop with flags and breaks. This is usually handy as we can make the updateContext and shouldBreak functions members of the Looper class. Of course in most cases this can be refactored to be even neater, depending on what your context is.

No comments:

Post a Comment