C++ test for within

I found myself having to write a bunch of range checking code like this:

if (val < 0.0 || val > 1.0)
    val = 1.0;

so I wrote this simple function.

const Type & within (const Type &lower, const Type &val, const Type &upper)
    return std::min (std::max (lower, val), upper);

So the above code gets simplified to:

val = within(0.0, val, 1.0);

I wasn’t happy about the extra copy being created but was willing to live with it.
Then I ran across this fragment which is so similar but ended up changing the final design:

if (val == 10)
    val = 5;

The difference is the above check sets an arbitrary value if it wasn’t within the range instead of just assigning one of the bounds to the value. That caused me to split it into a test, within(), to handle this case and a setwithin() to handle the earlier cases.
Splitting it also let me do a minor optimization. The typical case is that being out of bounds is rather exceptional and it’d be nice to avoid doing a copy. Accordingly, setwithin() checks if the dest has the same address as the replacement value and avoids doing the assignment.

int within (const Type &lower, const Type &val, const Type &upper)
    if (val < lower)
        return -1;
    if (upper < val)
        return 1;
    return 0;
int setwithin (const Type &lower, const Type & val, const Type & upper, Type & dest)
    int res = within (lower, val, upper);
    switch (res)
    case -1:
        if (&lower != &dest)
            dest = lower;
    case 0:
        if (&val != &dest)
            dest = val;
    case 1:
        if (&upper != &dest)
            dest = upper;
    return res;

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.