5

I'm currently trying to come up with a clever way of implementing flags that include the states "default" and (optional) "toggle" in addition to the usual "true" and "false".

The general problem with flags is, that one has a function and wants to define its behaviour (either "do something" or "don't do something") by passing certain parameters.

Single flag

With a single (boolean) flag the solution is simple:

void foo(...,bool flag){
    if(flag){/*do something*/}
}

Here it is especially easy to add a default, by just changing the function to

void foo(...,bool flag=true)

and call it without the flag parameter.

Multiple flags

Once the number of flags increases, the solution i usually see and use is something like this:

typedef int Flag;
static const Flag Flag1 = 1<<0;
static const Flag Flag2 = 1<<1;
static const Flag Flag3 = 1<<2;

void foo(/*other arguments ,*/ Flag f){
    if(f & Flag1){/*do whatever Flag1 indicates*/}
    /*check other flags*/
}

//call like this:
foo(/*args ,*/ Flag1 | Flag3)

This has the advantage, that you don't need a parameter for each flag, which means the user can set the flags he likes and just forget about the ones he don't care about. Especially you dont get a call like foo (/*args*/, true, false, true) where you have to count which true/false denotes which flag.

The problem here is:
If you set a default argument, it is overwritten as soon as the user specifies any flag. It is not possible to do somethink like Flag1=true, Flag2=false, Flag3=default.

Obviously, if we want to have 3 options (true, false, default) we need to pass at least 2 bits per flag. So while it might not be neccessary, i guess it should be easy for any implementation to use the 4th state to indicate a toggle (= !default).

I have 2 approaches to this, but i'm not really happy with both of them:

Approach 1: Defining 2 Flags

I tried using something like this up to now:

typedef int Flag;
static const Flag Flag1 = 1<<0;
static const Flag Flag1False= 1<<1;
static const Flag Flag1Toggle = Flag1 | Flag1False;
static const Flag Flag2= 1<<2;
static const Flag Flag2False= 1<<3;
static const Flag Flag2Toggle = Flag2 | Flag2False;

void applyDefault(Flag& f){
    //do nothing for flags with default false

    //for flags with default true:
    f = ( f & Flag1False)? f & ~Flag1 : f | Flag1;
    //if the false bit is set, it is either false or toggle, anyway: clear the bit
    //if its not set, its either true or default, anyway: set
}

void foo(/*args ,*/ Flag f){
    applyDefault(f);

    if (f & Flag1) //do whatever Flag1 indicates
}

However what i don't like about this is, that there are two different bits used for each flag. This leads to the different code for "default-true" and "default-false" flags and to the neccessary if instead of some nice bitwise operation in applyDefault().

Approach 2: Templates

By defining a template-class like this:

struct Flag{
  virtual bool apply(bool prev) const =0;
};

template<bool mTrue, bool mFalse>
struct TFlag: public Flag{
    inline bool apply(bool prev) const{
        return (!prev&&mTrue)||(prev&&!mFalse);
    }
};

TFlag<true,false> fTrue;
TFlag<false,true> fFalse;
TFlag<false,false> fDefault;
TFlag<true,true> fToggle;

i was able to condense the apply into a single bitwise operation, with all but 1 argument known at compile time. So using the TFlag::apply directly compiles (using gcc) to the same machine code as a return true;, return false;, return prev; or return !prev; would, which is pretty efficient, but that would mean i have to use template-functions if i want to pass a TFlag as argument. Inheriting from Flag and using a const Flag& as argument adds the overhead of a virtual function call, but saves me from using templates.

However i have no idea how to scale this up to multiple flags...

Question

So the question is: How can i implement multiple flags in a single argument in C++, so that a user can easily set them to "true", "false" or "default" (by not setting the specific flag) or (optional) indicate "whatever is not default"?

Is a class with two ints, using a similar bitwise operation like the template-approach with its own bitwise-operators the way to go? And if so, is there a way to give the compiler the option to do most of the bitwise operations at compile-time?

Edit for clarification: I don't want to pass the 4 distinct flags "true", "false", "default", "toggle" to a function.
E.g. think of a circle that gets drawn where the flags are used for "draw border", "draw center", "draw fill color", "blurry border", "let the circle hop up and down", "do whatever other fancy stuff you can do with a circle", ....
And for each of those "properties" i want to pass a flag with value either true, false, default or toggle. So the function might decide to draw the border, fill color and center by default, but none of the rest. A call, roughly like this:

draw_circle (DRAW_BORDER | DONT_DRAW_CENTER | TOGGLE_BLURRY_BORDER) //or
draw_circle (BORDER=true, CENTER=false, BLURRY=toggle)
//or whatever nice syntax you come up with....

should draw the border (specified by flag), not draw the center (specified by flag), blurry the border (the flag says: not the default) and draw the fill color (not specified, but its default).
If i later decide to not draw the center by default anymore but blurry the border by default, the call should draw the border (specified by flag), not draw the center (specified by flag), not blurry the border (now blurrying is default, but we don't want default) and draw the fill color (no flag for it, but its default).

Anedar
  • 4,235
  • 1
  • 23
  • 41
  • Why not use a kind of map of flags? You just then need to properly merge the maps (default and parameter) to get the flags... – Jean-Baptiste Yunès Jun 22 '16 at 14:04
  • Isn't a map extremely inefficient compared to these bitwise operations? And how would a function call look like then? – Anedar Jun 22 '16 at 14:14
  • 1
    I said kind of, not necessarily C++ map. Anyway one can imagine calling with `f(...,FlagMap(Flag1(true),Flag3(default),Flag17(toggle)));` or similar? Maybe a FlagSet?... – Jean-Baptiste Yunès Jun 22 '16 at 14:18
  • I'm not sure if it fits in my case (read: if i can teach the ones who shall use it to this system), but its an interesting idea to use such a "key-value" notation. – Anedar Jun 22 '16 at 14:23
  • What about `std::vector`? – Mine Jun 22 '16 at 14:38
  • How would you efficiently merge them with defaults? Or define constants for them? – Anedar Jun 22 '16 at 15:08
  • If it is really so important to you that callers be able to take advantage of defaults, you might consider using a fluent interface (i.e., via cascading calls to "property"-like member functions). This would certainly be more natural and more understandable (to me at least) then either of your proposed alternatives. But if it were me, I'd just use the standard flags idiom. Make the "defaults" easy to reason about: if the flag is not passed, the operation doesn't happen. Keep the flags *consistent*, so that they all turn *on* (or off) an action, rather than some turning it on and some off. – Cody Gray - on strike Jun 23 '16 at 11:00

5 Answers5

1

Not exactly pretty, but very simple (building from your Approach 1):

#include <iostream>

using Flag = int;
static const Flag Flag1 = 1<<0;
static const Flag Flag2 = 1<<2;
// add more flags to turn things off, etc.

class Foo
{
    bool flag1 = true;      // default true
    bool flag2 = false;     // default false

    void applyDefault(Flag& f)
    {
        if (f & Flag1)
            flag1 = true;
        if (f & Flag2)
            flag2 = true;
        // apply off flags
    }

public:
    void operator()(/*args ,*/ Flag f)
    {
        applyDefault(f);
        if (flag1)
            std::cout << "Flag 1 ON\n";
        if (flag2)
            std::cout << "Flag 2 ON\n";
    }
};

void foo(/*args ,*/ Flag flags)
{
    Foo f;
    f(flags);
}

int main()
{
    foo(Flag1); // Flag1 ON
    foo(Flag2); // Flag1 ON\nFlag2 ON
    foo(Flag1 | Flag2); // Flag1 ON\nFlag2 ON
    return 0;
}
Leben Asa
  • 307
  • 1
  • 6
  • I like your idea of turning the function into a class. Did i get you right, to turn things off, one would define something like `static const Flag NoFlag1 = 1<<1;` and add `if (f & NoFlag1) flag1=false;`to the `applyDefault`? – Anedar Jun 22 '16 at 18:27
  • Yes. To be fair it doesn't have to use class, but sometimes lazy programmer like myself love to switch things one flag at a time. Simple POD helps there. – Leben Asa Jun 23 '16 at 05:22
1

Your comments and answers pointed me towards a solution that i like and wanted to share with you:

struct Default_t{} Default;
struct Toggle_t{} Toggle;

struct FlagSet{
    uint m_set;
    uint m_reset;

    constexpr FlagSet operator|(const FlagSet other) const{
        return {
            ~m_reset & other.m_set & ~other.m_reset |
            ~m_set & other.m_set & other.m_reset |
            m_set & ~other.m_set,
            m_reset & ~other.m_reset |
            ~m_set & ~other.m_set & other.m_reset|
            ~m_reset & other.m_set & other.m_reset};
    }

    constexpr FlagSet& operator|=(const FlagSet other){
        *this = *this|other;
        return *this;
    }
};

struct Flag{
    const uint m_bit;

    constexpr FlagSet operator= (bool val) const{
        return {(uint)val<<m_bit,(!(uint)val)<<m_bit};
    }

    constexpr FlagSet operator= (Default_t) const{
        return {0u,0u};
    }

    constexpr FlagSet operator= (Toggle_t) const {
        return {1u<<m_bit,1u<<m_bit};
    }

    constexpr uint operator& (FlagSet i) const{
        return i.m_set & (1u<<m_bit);
    }

    constexpr operator FlagSet() const{
        return {1u<<m_bit,0u}; //= set
    }

    constexpr FlagSet operator|(const Flag other) const{
        return (FlagSet)*this|(FlagSet)other;
    }
    constexpr FlagSet operator|(const FlagSet other) const{
        return (FlagSet)*this|other;
    }
};

constexpr uint operator& (FlagSet i, Flag f){
    return f & i;
}

So basically the FlagSet holds two integers. One for set, one for reset. Different combinations represent different actions for that particular bit:

{false,false} = Default (D)
{true ,false} = Set (S)
{false,true } = Reset (R)
{true ,true } = Toggle (T)

The operator| is using a rather complex bitwise operation, designed to fullfill

D|D = D
D|R = R|D = R
D|S = S|D = S
D|T = T|D = T
T|T = D
T|R = R|T = S
T|S = S|T = R
S|S = S
R|R = R
S|R = S  (*)
R|S = R  (*) 

The non-commutative behaviour in (*) is due to the fact, that we somehow need the ability to decide which one is the "default" and which one is the "user defined" one. So in case of conflicting values, the left one takes precedence.

The Flag class represents a single flag, basically one of the bits. Using the different operator=() overloads enables some kind of "Key-Value-Notation" to convert directly to a FlagSet with the bit-pair at position m_bit set to one of the previously defined pairs. By default (operator FlagSet()) this converts to a Set(S) action on the given bit.
The class also provides some overloads for bitwise-OR that auto convert to FlagSet and operator&() to actually compare the Flag with a FlagSet. In this comparison both Set(S) and Toggle(T) are considered true while both Reset(R) and Default(D) are considered false.

Using this is incredibly simple and very close to the "usual" Flag-implementation:

constexpr Flag Flag1{0};
constexpr Flag Flag2{1};
constexpr Flag Flag3{2};

constexpr auto NoFlag1 = (Flag1=false); //Just for convenience, not really needed;


void foo(FlagSet f={0,0}){
    f |= Flag1|Flag2; //This sets the default. Remember: default right, user left
    cout << ((f & Flag1)?"1":"0");
    cout << ((f & Flag2)?"2":"0");
    cout << ((f & Flag3)?"3":"0");
    cout << endl;
}

int main() {

    foo();
    foo(Flag3);
    foo(Flag3|(Flag2=false));
    foo(Flag3|NoFlag1);
    foo((Flag1=Toggle)|(Flag2=Toggle)|(Flag3=Toggle));

    return 0;
}

Output:

120
123
103
023
003

Test it on ideone

One last word about efficiency: While i didn't test it without all the constexpr keywords, with them this code:

bool test1(){
  return Flag1&((Flag1=Toggle)|(Flag2=Toggle)|(Flag3=Toggle));
}

bool test2(){
  FlagSet f = Flag1|Flag2 ;
  return f & Flag1;
}

bool test3(FlagSet f){
  f |= Flag1|Flag2 ;
  return f & Flag1;
}

compiles to (usign gcc 5.3 on gcc.godbolt.org)

test1():
    movl    $1, %eax
    ret
test2():
    movl    $1, %eax
    ret
test3(FlagSet):
    movq    %rdi, %rax
    shrq    $32, %rax
    notl    %eax
    andl    $1, %eax
    ret

and while i'm not totally familiar with Assembler-Code, this looks like very basic bitwise operations and probably the fastest you can get without inlining the test-functions.

Anedar
  • 4,235
  • 1
  • 23
  • 41
0

If I understand the question you can solve the problem by creating a simple class with implicit constructor from bool and default constructor:

class T
{
    T(bool value):def(false), value(value){} // implicit constructor from bool
    T():def(true){}

    bool def; // is flag default
    bool value; // flag value if flag isn't default
}

and using it in function like this:

void f(..., T flag = T());


void f(..., true); // call with flag = true
void f(...); // call with flag = default
  • Hmm, i don't see how to use this for multiple flags. I would like to avoid having a parameter for each flag and have something closer to the version in "Multiple flags". So what is the benefit of this over using just a bool? – Anedar Jun 22 '16 at 14:16
  • Oh, I see. Looks like I didn't understand the question. – Sergey Krivohatskiy Jun 22 '16 at 14:42
  • Do you want to have something like `kwargs` in python? I've found an implementation of it in c++ based on templates. I'm not sure it's fast enough, but you may take a look: https://github.com/cheshirekow/kwargs – Sergey Krivohatskiy Jun 22 '16 at 14:51
  • This looks interesting – Anedar Jun 22 '16 at 15:21
0

If I understand correctly, you want a simple way to pass one or more flags to a function as a single parameter, and/or a simple way for an object to keep track of one or more flags in a single variable, correct? A simple approach would be to specify the flags as a typed enum, with an unsigned underlying type large enough to hold all the flags you need. For example:

/* Assuming C++11 compatibility.  If you need to work with an older compiler, you'll have
 * to manually insert the body of flag() into each BitFlag's definition, and replace
 * FLAG_INVALID's definition with something like:
 *   FLAG_INVALID = static_cast<flag_t>(-1) -
 *                   (FFalse + FTrue + FDefault + FToggle),
 */

#include <climits>
// For CHAR_BIT.
#include <cstdint>
// For uint8_t.

// Underlying flag type.  Change as needed.  Should remain unsigned.
typedef uint8_t flag_t;

// Helper functions, to provide cleaner syntax to the enum.
// Not actually necessary, they'll be evaluated at compile time either way.
constexpr flag_t flag(int f) { return 1 << f; }
constexpr flag_t fl_validate(int f) {
    return (f ? (1 << f) + fl_validate(f - 1) : 1);
}
constexpr flag_t register_invalids(int f) {
    // The static_cast is a type-independent maximum value for unsigned ints.  The compiler
    //  may or may not complain.
    // (f - 1) compensates for bits being zero-indexed.
    return static_cast<flag_t>(-1) - fl_validate(f - 1);
}

// List of available flags.
enum BitFlag : flag_t {
    FFalse   = flag(0),  // 0001
    FTrue    = flag(1),  // 0010
    FDefault = flag(2),  // 0100
    FToggle  = flag(3),  // 1000

    // ...

    // Number of defined flags.
    FLAG_COUNT = 4,
    // Indicator for invalid flags.  Can be used to make sure parameters are valid, or
    // simply to mask out any invalid ones.
    FLAG_INVALID = register_invalids(FLAG_COUNT),
    // Maximum number of available flags.
    FLAG_MAX = sizeof(flag_t) * CHAR_BIT
};

// ...

void func(flag_t f);

// ...

class CL {
    flag_t flags;

    // ...
};

Note that this assumes that FFalse and FTrue should be distinct flags, both of which can be specified at the same time. If you want them to be mutually exclusive, a couple small changes would be necessary:

// ...
constexpr flag_t register_invalids(int f) {
    // Compensate for 0th and 1st flags using the same bit.
    return static_cast<flag_t>(-1) - fl_validate(f - 2);
}
// ...
enum BitFlag : flag_t {
    FFalse   = 0,        // 0000
    FTrue    = flag(0),  // 0001
    FDefault = flag(1),  // 0010
    FToggle  = flag(2),  // 0100
// ...

Alternatively, instead of modifying the enum itself, you could modify flag():

// ...
constexpr flag_t flag(int f) {
    // Give bit 0 special treatment as "false", shift all other flags down to compensate.
    return (f ? 1 << (f - 1) : 0);
}
// ...
constexpr flag_t register_invalids(int f) {
    return static_cast<flag_t>(-1) - fl_validate(f - 2);
}
// ...
enum BitFlag : flag_t {
    FFalse   = flag(0),  // 0000
    FTrue    = flag(1),  // 0001
    FDefault = flag(2),  // 0010
    FToggle  = flag(3),  // 0100
// ...

While I believe this to be the simplest approach, and possibly the most memory-efficient if you choose the smallest possible underlying type for flag_t, it is likely also the least useful. [Also, if you end up using this or something similar, I would suggest hiding the helper functions in a namespace, to prevent unnecessary clutter in the global namespace.]

A simple example.

  • Thanks for your effort, but i think you missunderstood my question, since i want to be able to indicate the four states for every property/bit/flag/however you call it. See my edit and my answer for further clarification. – Anedar Jun 23 '16 at 00:19
  • @Anedar Ah, okay. Glad you found something that works for you. – Justin Time - Reinstate Monica Jun 23 '16 at 19:19
0

Is there a reason we cannot use an enum for this? Here is a solution that I have used recently:

// Example program
#include <iostream>
#include <string>

enum class Flag : int8_t
{
    F_TRUE      = 0x0, // Explicitly defined for readability
    F_FALSE     = 0x1,
    F_DEFAULT   = 0x2,
    F_TOGGLE    = 0x3

};

struct flags
{
    Flag flag_1;
    Flag flag_2;
    Flag flag_3;
    Flag flag_4;
};

int main()
{

  flags my_flags;
  my_flags.flag_1 = Flag::F_TRUE;
  my_flags.flag_2 = Flag::F_FALSE;
  my_flags.flag_3 = Flag::F_DEFAULT;
  my_flags.flag_4 = Flag::F_TOGGLE;

  std::cout << "size of flags: " << sizeof(flags) << "\n";
  std::cout << (int)(my_flags.flag_1) << "\n";
  std::cout << (int)(my_flags.flag_2) << "\n";
  std::cout << (int)(my_flags.flag_3) << "\n";
  std::cout << (int)(my_flags.flag_4) << "\n";

}

Here, we get the following output:

size of flags: 4
0
1
2
3

It's not quite memory efficient this way. Each Flag is 8 bits compared to two bools at one bit each, for a 4x memory increase. However, we are afforded the benefits of enum class which prevents some stupid programmer mistakes.

Now, I have another solution for when memory is critical. Here we pack 4 flags into an 8-bit struct. This one I came up with for a data editor, and it worked perfectly for my uses. However there may be downsides that I am now aware of.

// Example program
#include <iostream>
#include <string>

enum Flag
{
    F_TRUE      = 0x0, // Explicitly defined for readability
    F_FALSE     = 0x1,
    F_DEFAULT   = 0x2,
    F_TOGGLE    = 0x3

};

struct PackedFlags
{
public:
    bool flag_1_0:1;
    bool flag_1_1:1;
    bool flag_2_0:1;
    bool flag_2_1:1;
    bool flag_3_0:1;
    bool flag_3_1:1;
    bool flag_4_0:1;
    bool flag_4_1:1;

public:
    Flag GetFlag1()
    {
        return (Flag)(((int)flag_1_1 << 1) + (int)flag_1_0);
    }
    Flag GetFlag2()
    {
        return (Flag)(((int)flag_2_1 << 1) + (int)flag_2_0);
    }
    Flag GetFlag3()
    {
        return (Flag)(((int)flag_3_1 << 1) + (int)flag_3_0);
    }
    Flag GetFlag4()
    {
        return (Flag)(((int)flag_4_1 << 1) + (int)flag_4_0);
    }

    void SetFlag1(Flag flag)
    {
        flag_1_0 = (flag & (1 << 0));
        flag_1_1 = (flag & (1 << 1));
    }
    void SetFlag2(Flag flag)
    {
        flag_2_0 = (flag & (1 << 0));
        flag_2_1 = (flag & (1 << 1));
    }
    void SetFlag3(Flag flag)
    {
        flag_3_0 = (flag & (1 << 0));
        flag_3_1 = (flag & (1 << 1));
    }
    void SetFlag4(Flag flag)
    {
        flag_4_0 = (flag & (1 << 0));
        flag_4_1 = (flag & (1 << 1));
    }

};

int main()
{

  PackedFlags my_flags;
  my_flags.SetFlag1(F_TRUE);
  my_flags.SetFlag2(F_FALSE);
  my_flags.SetFlag3(F_DEFAULT);
  my_flags.SetFlag4(F_TOGGLE);

  std::cout << "size of flags: " << sizeof(my_flags) << "\n";
  std::cout << (int)(my_flags.GetFlag1()) << "\n";
  std::cout << (int)(my_flags.GetFlag2()) << "\n";
  std::cout << (int)(my_flags.GetFlag3()) << "\n";
  std::cout << (int)(my_flags.GetFlag4()) << "\n";

}

Output:

size of flags: 1
0
1
2
3
Community
  • 1
  • 1