Hello everybody,
I want to know if some people are interested in a type-safe flagsets. I
define flagsets as a container similar to a bitset, but where each bit has
a meaning.
For example, we could have in some game :
enum Direction : unsigned {
UP = 0b0001,
DOWN = 0b0010,
LEFT = 0b0100,
RIGHT = 0b1000
};
...
unsigned player_dir = UP | RIGHT;
if ((player_dir & (UP|LEFT)) == (UP|LEFT))
player.setAnim("up_left");
player_dir &= ~UP; //removing UP from player_dir
I think there are some issues with this kind of flagset :
- you need to think about power-of-twos when attributing values to your
flags.
- you need to use bitwise operations which can be non-trivial, even for
removing only one flag.
- it is not safe:
for example with another flagset using the flag INIT_VIDEO (in a window
library like SDL),
you can do " UP | INIT_VIDEO " even if the two flagsets have nothing in
common
With a type-safe flagset library, this code would become :
namespace Direction {
struct UP;
struct DOWN;
struct LEFT;
struct RIGHT;
using Type = flagset
On 25/06/2018 06:43, Julien Vernay wrote:
I think there are some issues with this kind of flagset : - you need to think about power-of-twos when attributing values to your flags. - you need to use bitwise operations which can be non-trivial, even for removing only one flag. - it is not safe: for example with another flagset using the flag INIT_VIDEO (in a window library like SDL), you can do " UP | INIT_VIDEO " even if the two flagsets have nothing in common
Note that C++11's scoped enums solve those safety issues. And if you don't care about the specific bit values (eg. you don't need to directly serialize the value or interoperate with an external API), then you can use bitfields, which resolve all of those issues (albeit with other limitations). Does your approach allow you to predefine standard combinations of flags (eg. defining UP_LEFT = UP | LEFT)? That's a common requirement for these sorts of things.
The aim is that each flag is independent, so you can have two flags active
at a same time, while an enum should have only one value at a time.
Scoped enums do not solve those issues because they can not be combined, if
you want to combine them you first need to used "static_cast" for
converting it to an int, then using & | ^ to combine them.
For predefining standard combination of flags, as UP_LEFT, you can do :
constexpr auto UP_LEFT =
Direction::Type::ValueDirection::UP,Direction::LEFT();
Thanks for your answer !
2018-06-25 2:47 GMT+02:00 Gavin Lambert via Boost
On 25/06/2018 06:43, Julien Vernay wrote:
I think there are some issues with this kind of flagset : - you need to think about power-of-twos when attributing values to your flags. - you need to use bitwise operations which can be non-trivial, even for removing only one flag. - it is not safe: for example with another flagset using the flag INIT_VIDEO (in a window library like SDL), you can do " UP | INIT_VIDEO " even if the two flagsets have nothing in common
Note that C++11's scoped enums solve those safety issues.
And if you don't care about the specific bit values (eg. you don't need to directly serialize the value or interoperate with an external API), then you can use bitfields, which resolve all of those issues (albeit with other limitations).
Does your approach allow you to predefine standard combinations of flags (eg. defining UP_LEFT = UP | LEFT)? That's a common requirement for these sorts of things.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman /listinfo.cgi/boost
On 25/06/2018 18:09, Julien Vernay wrote:
The aim is that each flag is independent, so you can have two flags active at a same time, while an enum should have only one value at a time. Scoped enums do not solve those issues because they can not be combined, if you want to combine them you first need to used "static_cast" for converting it to an int, then using & | ^ to combine them.
For that, I like the approach in this answer: https://softwareengineering.stackexchange.com/a/338472/303655 Where you use a standard (non-power-of-two) enum to define the bit positions, and a separate class that turns it into a bitset. If you do want to explicitly define the power-of-two values, then you can use something like this instead: https://github.com/grisumbras/enum-flags
Did you (or would you) consider to provide other 'concepts', like triboolsets (trits) (indeterminate values) or floating point values, the latter for example expressing closeness or energy levels? degski -- *"If something cannot go on forever, it will stop" - Herbert Stein*
For that, I like the approach in this answer: https://softwareengineering.stackexchange.com/a/338472/303655
indeed it is a good approach, is there a reason why something similar to this is not part of Boost ? Did you (or would you) consider to provide other 'concepts', like
triboolsets (trits) (indeterminate values) or floating point values
Triboolsets could be a possibility (even if not sure of the purpose), but
providing other concepts as floating point or int is too specific to an
application and I think it should have its own type.
2018-06-26 7:21 GMT+02:00 degski via Boost
Did you (or would you) consider to provide other 'concepts', like triboolsets (trits) (indeterminate values) or floating point values, the latter for example expressing closeness or energy levels?
degski -- *"If something cannot go on forever, it will stop" - Herbert Stein*
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/ mailman/listinfo.cgi/boost
On 26 June 2018 at 16:15, Julien Vernay via Boost
Triboolsets could be a possibility (even if not sure of the purpose) ...
One could use them for something like G.O.A.P. https://github.com/stolk/GPGOAP
... but providing other concepts as floating point or int is too specific to an application and I think it should have its own type.
Once one has adopted the idea of "flags" to possibly not exist, i.e. not to be either true or false, a natural extension is to adopt "fuzzy flags" as well, i.e. use floats. Some bike-shedding: I think the word flags is not sufficiently general. degski -- *"If something cannot go on forever, it will stop" - Herbert Stein*
On 27/06/2018 01:41, degski wrote:
Once one has adopted the idea of "flags" to possibly not exist, i.e. not to be either true or false, a natural extension is to adopt "fuzzy flags" as well, i.e. use floats. Some bike-shedding: I think the word flags is not sufficiently general.
At this point you've sufficiently departed the "bitwise operations" model to make it fairly meaningless. You'd probably be better served with a regular structure or with Boost.ProgramOptions instead.
On 27 June 2018 at 02:37, Gavin Lambert via Boost
On 27/06/2018 01:41, degski wrote:
Once one has adopted the idea of "flags" to possibly not exist, i.e. not to be either true or false, a natural extension is to adopt "fuzzy flags" as well, i.e. use floats. Some bike-shedding: I think the word flags is not sufficiently general.
At this point you've sufficiently departed the "bitwise operations" model to make it fairly meaningless.
You would implement trits with bitwise operations using BCT (Binary Coded Ternary: implementation http://homepage.divms.uiowa.edu/~jones/ternary/libtern.shtml). Ternaries have some interesting mathematical properties as well, which is explained here https://en.wikipedia.org/wiki/Redundant_binary_representation. There are also pratical applications https://en.wikipedia.org/w/index.php?title=Ternary_numeral_system&action=edit§ion=4. You'd probably be better served with a regular structure or with
Boost.ProgramOptions instead.
Did you read the G.O.A.P. link I posted (here's one from MIT http://alumni.media.mit.edu/%7Ejorkin/goap.html)? Because if you had, you would not suggest to solve this problem with Boost.ProgramOptions. As to the fuzzy idea, bits are not necessarily digital, think analog computers. Personally, I think the flags proposal is an instance of over-engineering and is making things that are fairly simple (and why not use bitfields, the compiler does the work, certainly better than any had-coded solution) complicated. It is also a well-known and understood idea. degski
participants (3)
-
degski
-
Gavin Lambert
-
Julien Vernay