RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Enum data type, FLAGS, and Bitwise operations explained. (hopefully)

Lokai

Knight
Enum data type, FLAGS, and Bitwise operations explained. (hopefully)

Enum data type, FLAGS, and Bitwise operations explained. (hopefully)
TUTORIAL LEVEL: Intermediate.

Enum:
Description: A strongly typed collection of keywords, representing constants of any simple data type, except string.

Examples:
Code:
public enum MyIntegerEnum
{
     One = 1, Two = 2, Three = 3, Four = 4
}
 
public enum MyDoubleEnum
{
     One = 1.0, Two = 2.0, Three = 3.0, Four = 4.0
}
An enum data type can be used with the "." (dot) notation.
MyIntegerEnum.One
MyIntegerEnum.Two
etc.

Conversions between an enum and it's integral type need to be "cast" explicitly.

Code:
int testInteger = (int)MyIntegerEnum.One;

This would result in the variable 'testInteger' receiving the value '1'.

If you declare an enum without specifying the values, it is assumed the values are integers. The values are also assumed to increment by '1' in order of how they are displayed. (NOT necessarily in alphabetical order!) This is very important, since you can declare them out of alphabetical sequence, but when you see them displayed in a list, such as within Visual Studio's Context-Sensitive help, it displays them in alphabetical order.

Example:
Code:
public enum Shapes
{
Circle, Square, Triangle, Octagon, Pentagon
}
By default, Shapes.Circle has a value of '0', and Shapes.Pentagon has a value of 4.

Flags:
Description:
Flags is an Attribute you can assign to an enum. It lets the compiler know that the enum contains values which can be operated on using Bitwise notation. These are important, since it allows you to assign multiple values to a single variable. Here's how it works:

When you declare a 'Flags'-variety of the enum data type, you will usually declare them using the hexadecimal integers beginning with 0x0 or 0x1. The number of zeros immediately after the 'x' does not matter, but you should use as many as you need to visually distinguish the numbers.

For example, 0x1 and 0x01 are both equal to '1', but 0x10 is not. 0x10 is the hex value '10' or the decimal value '16'. By adding leading zeros, we can line up the numbers visually, so that their values are easier to view and compare. For example:

Code:
[FLAGS]
public enum MyFlags
{
     FirstFlag = 0x00001,
     NextFlag = 0x00002,
     AnotherFlag = 0x00004,
     FourthFlag = 0x00008,
     FifthFlag = 0x00010,
     LastFlag = 0x00020
}
By using the FLAGS keyword, we can now store multiple values in a single variable. (This is a simplified description, but it should help.) Here is one way we can store the variables:

Code:
private MyFlags m_Flags = MyFlags.FirstFlag | MyFlags.FourthFlag | MyFlags.LastFlag;

The '|' (pipe symbol, also known as the 'OR' symbol) is a Bitwise operator called the 'OR' operator. In English, this means my private variable 'm_Flags' is equal to FirstFlag OR FourthFlag OR LastFlag. In other words, any of those values are 'True' for my variable. In English, we might also say that my variable 'm_Flags is equal to 0x00001 AND 0x00008 AND 0x00020, or: 0x00001 + 0x00008 + 0x00020 = 0x00029. As you can see, 0x00029 is not listed in my enum as one of the values, but rather it is a combination of 3 values. To understand how these operations work in greater detail, and to understand more about Bitwise operations in general, I will try to explain about the bits themselves.

Bitwise operations:
Bits are zeros and ones. A '0' (Zero) represents 'off' or 'false', and a '1' (One) represents 'on' or 'true'. When displayed as a single series of numbers, each 'Bit' actually represents a much different number than either '0' or '1'. For example, the number 00101001 is equal to the decimal number '41'. Here is how we figure that out:

Code:
Value    128    64    32    16    8    4    2    1
Variable    0     0     1      0      1    0    0    1

Values in bitwise notation go from right to left, starting with '1' on the far right, and doubling each successive number to the left. If our variable has a '1' in that column, then the value is 'turned on', and if the variable has a '0', then the value is 'turned off' for that column. In this case, the '1', '8', and '32' columns are 'turned on', so we just add those numbers together to get 32+8+1=41.

So, what does this have to do with our 'MyFlags' enum?

Well, the values we used are actually the same. 0x00029 is equal to (decimal) 41.
Here is the table displayed using Hexadecimal numbers:

Code:
Value          0x00080       0x00040        0x00020       0x00010      0x00008      0x00004      0x00002    0x00001
Variable        0                0                    1                0                1                0                0                1

OK, so lets say we understand all that so far, what does that have to do with the '|' (bitwise OR) operator?
To understand bitwise operations, we need to display the bits again, this time separately:

Code:
Value       128    64    32    16    8    4    2    1
FirstFlag      0     0     0      0      0    0    0    1
FourthFlag    0     0     0      0      1    0    0    0
LastFlag       0     0     1      0      0    0    0    0

Now let's convert these to 'logical' or 'Boolean' values:

Code:
VALUE       128      64       32       16        8         4         2        1
FirstFlag      false    false    false    false    false    false    false    true
FourthFlag    false    false    false    false    true    false    false    false
LastFlag      false     false     true    false    false    false    false    false

OK, now lets compare each column, using 'OR' logic.

What is the answer to this: false OR false OR false. Of course, the answer is 'false'. How about the '32' column? 'false' OR 'false' OR 'true'. Well, the 'OR' operator says that if any of the values is true, the whole statement is true. So, the '32' column results in 'true'. The same is true for the '8' and '1' columns.
What about the bitwise 'AND' operator ('&')?

The '&' operator uses logical 'AND' to compare two or more values. If we were to apply this to our Flags, we could evaluate the existence of a particular flag or set of flags in a variable. For example, to see if MyFlags.FourthFlag can be found in m_Flags, we use the '&' operator like this: Here we show our test variable m_Flags, along with the constant FourthFlag.
Code:
Value       128    64    32    16    8    4    2    1
m_Flags       0     0     1      0      1    0    0    1
FourthFlag    0     0     0      0      1    0    0    0
Next, we will convert these to Boolean values:
Code:
VALUE       128      64       32       16        8         4         2        1
m_Flags       false    false    true     false    true     false    false    true
FourthFlag    false    false    false    false    true    false    false    false
Now, lets use our Logical 'AND' operation to compare the numbers. In Bitwise comparisons, only if BOTH values are 'true' is the resulting comparison true.
Code:
false AND false = [COLOR=#800000]false[/COLOR]
false AND true = [COLOR=#800000]false[/COLOR]
true AND true = [COLOR=#008000][B]true[/B][/COLOR]
true AND false = [COLOR=#800000]false[/COLOR]
In this case, the result is that ONLY the '8' column results in a 'true' value, so m_Flags & MyFlags.FourthFlag = MyFlags.FourthFlag. In other words, when we looked in our variable 'm_Flags' for the value 'FourthFlag', we FOUND IT! What if we were looking for AnotherFlag instead? OK, here would be our new table:
Code:
VALUE       128      64       32       16        8         4         2        1
m_Flags       false    false    true     false    true     false    false    true
AnotherFlag    false    false    false    false    false    true    false    false
In this case, the result is ALL of the columns are FALSE. This means, when we looked in m_Flags, trying to find AnotherFlag, we did NOT find it! Of course, that is what we were expecting, but now you know how that works behind the scenes.

One more operator I want to explain is the '~' (complement) operator. Basically, it inverts all values in a number. So, the complement of 'true' is 'false', and vice versa. Here is how it would look with our variable 'm_Flags':
Code:
VALUE       128      64       32       16        8         4         2        1
m_Flags       false    false    true     false    true     false    false    true
~m_Flags     true     true     false    true     false    true     true     false
Here is how it looks with MyFlags.FourthFlag:
Code:
VALUE       128      64       32       16        8         4         2        1
FourthFlag    false    false    false    false    true    false    false    false
~FourthFlag    true    true    true    true     false    true    true    true
If we were to use a complement operation on a single variable, the result would always be '0' or 'false' for every column, so we can use this knowledge, along with our understanding of the '|' and '&' operators, to set a Flag in a variable. Here's how: Let's say we want to set AnotherFlag to 'true' in our test variable 'm_Flags'. To do this is very simple, we just use the '|' (bitwise OR) operator like this:
Code:
 m_Flags = m_Flags | MyFlags.AnotherFlag;
Why does this work? Remember, I set the flags in m_Flags originally in the same way. In English, what I am saying is this: "m_Flags is equal to all of the existing flags that are enabled in m_Flags currently, OR MyFlags.AnotherFlag." By using the 'Logical OR' it is kind of like simple addition, remember? Since any of the values can be true to make the whole thing true, the 'OR' operation is adding the new value to the existing variable.

There are other Bitwise operators, such as the Shift '>>' and '<<' operators, but the ones I have explained so far are sufficient for this tutorial.
Let's see how this is used in a well-known RunUO script: PlayerMobile.cs:

Code:
public bool GetFlag( PlayerFlag flag )
{
    return ( (m_Flags & flag) != 0 );
}
 
public void SetFlag( PlayerFlag flag, bool value )
{
    if ( value )
        m_Flags |= flag;
    else
        m_Flags &= ~flag;
}
These two methods are used to get or set a particular PlayerFlag in the m_Flags variable which is part of every Player.
If the value exists in m_Flags, we can find that by calling the 'GetFlag' method. What the 'return' line says is this: if m_Flags 'AND' the flag we are looking for result in a '0' value, then return false, otherwise, return true. Remember we saw this before in our test when we were looking for 'AnotherFlag' in our variable:
Code:
VALUE       128      64       32       16        8         4         2        1
m_Flags       false    false    true     false    true     false    false    true
AnotherFlag    false    false    false    false    false    true    false    false
The result was each column returned 'false' when the two rows were compared using the '&' operator.

In the SetFlag method, we have 2 possible statements, 'if (value)' and 'else'; or in other words, if the value we are setting is 'true' then "we run the first statement" else "we run the second statement."

Let's look at each statement.
Code:
 m_Flags |= flag;
This is the same as saying this:
Code:
 m_Flags = m_Flags | flag;
We have seen this before. We know we can set a flag, or turn 'ON' a flag, or set it to 'true' by using the '|' (Bitwise OR) operator.
But what about the other statement?
Code:
 m_Flags &= ~flag;
OK, this is the same as this:
Code:
 m_Flags = m_Flags & ~flag;
Remember what the '~' operator does? It is called the complement operator, and it basically inverts a value, meaning it gives you the opposite. Let's look at what this would look like if we did this operation using our test variable and our table. If 'flag' was 'MyFlags.AnotherFlag' (which is equal to '4') here is what the table would look like:
Code:
& operation    128    64     32     16       8         4         2         1
m_Flags       false    false    true    false    true    false    false    true    
~flag (~4)     true    true    true    true     true    false     true    true
result: -->     false    false    true    false    true    false    false    true
As you can see, this does not change the value, because we are trying to turn OFF a value that is already OFF. But what if we were to do the same thing with 'MyFlags.FourthFlag' (which is equal to '8')? Here is what the table would look like:
Code:
& operation    128    64     32     16       8         4         2         1
m_Flags       false    false    true    false    true    false    false    true    
~flag (~8)     true    true    true    true     false     true    true    true
result: -->     false    false    true    false    false    false    false    true
This would successfully set the flag 'OFF' since true AND false == false.
 
Top