Jump to content

Bit-flagging in Second Life


Malinda Quartz
 Share

You are about to reply to a thread that has been inactive for 2772 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

EDIT, Sep 17: I'm going to periodically edit this post so to try and make it look more presentable and easier to understand. I started this topic because after searching both the forums and the lsl portal, I'd noticed there's not much discussion or any tutorials emphasizing on bit-flags or any bit manipulation for that matter. So someone once said "If you truly want something done? Gotta do it yourself." So here I am. My hope is that this will benefit new-comers and students learning  to code who are not so familiar with the rundowns.

Hi everyone. Just thought I'd toss in a contribution: Why use multiple global integers when you can just use one to toggle multiple bit-flags each exclusively via XOR? Bit-flags are used to prevent an unnecessary stack of 32 bit integers that would be used to toggle things.

How do we visualize bits within an LSL integer:

Take a look at this;

integer glb_tog = 0; //32 bit

glb_tog looks like [00000000 00000000 00000000 00000000] That's a big row of binary zeros. Count those zeros, that's 32 or 32 bits. The green bits are going to be manipulated (within the snippet below) and we'll leave red one's alone. Let's extrapolate the big row some more:

Hexadecimals to "address" the bits.

0x01 = 00000001

0x02 = 00000010

0x04 = 00000100

0x08 = 00001000

0x10 = 00010000

 The positioning: [00000000 00000000 00000000 0001₁₀ 1₀₈ 1₀₄ 1₀₂ 1₀₁] All bit-flags in position.

These selected hexadecimal numbers are chosen because they share one thing in common, they are all single 1 binary digits. That's important to know when xoring any integer against it's bits without the use of bit-shifting as opposed to non-single binary digits such as "0x03 = 00000011".

So whenever we toggle a single bit with the xor operator ^:

glb_tog = glb_tog ^ 0x04; // Hit!

We get this outcome: [00000000 00000000 00000000 00000100] bit-flag in position 3 is switched on.

glb_tog = glb_tog ^ 0x04; // Hit again!

Outcome: [00000000 00000000 00000000 00000000] bit-flag in position 3 is switched off.

So without further adieu:

 Example Snippet (imperative style) for basic and intermediate levels:

// Using only one global integer to control five toggles for the purpose
// of better memory optimization - By the owner of Second Life Avatar:
// Malinda Quartz (Sat Sep 17, 2016) Updated.
 
// This script is....GPL licensed. Why not..
 
// Okay so basically: Why use five global integers
// when you can just have one toggling five bit-flags
// each exclusively? You can control up to 32 toggles
// into one SL integer but for this example we'll just do five. // Instructions: ctrl-c & v this script into a prim within Second Life // and save. Type in public chat using channel 22: either // "bit1" or "bit2" or "bit3" or "bit4" or "bit5" without quotes // and watch them toggle ON/OFF. Example "/22 bit4" without quotes. // Lazy Lists: // In LSL never declare a "bit" globally or locally for that matter.
// If you need to put titles on your bits, macro define them with a
// compiler that supports pre-processing so to avoid doubling your
// byte cost on each one.
// If you have a viewer that doesn't support pre-proccessing then
// add your bit digits directly into their scopes. You can add them as
// hexadecimal or decimal but I prefer hex. #define lzy_bit1 0x01 // "00000001" = "1" #define lzy_bit2 0x02 // "00000010" = "2" #define lzy_bit3 0x04 // "00000100" = "4" #define lzy_bit4 0x08 // "00001000" = "8" #define lzy_bit5 0x10 // "00010000" = "16" // Just one integer 32 bit [00000000 00000000 00000000 00000000].. integer glb_tog; default { state_entry() { llListen(22,"",NULL_KEY,""); } listen(integer c, string n, key i, string m) { key r = llGetOwnerKey(i); key x = llGetOwner(); if (r != x) return; else { string t; // Why can't we just do "glb_tog ^= bit-flag"? (C++) It's // more succinct but it just won't compile that way. So // "glb_tog = glb_tog ^ bit-flag" (old school) will // have to do instead. Anyway, toggle using XOR.. if ("bit1" == m) { glb_tog = glb_tog ^ lzy_bit1;// ON/OFF if (glb_tog & lzy_bit1) t = "Bit-flag1 is toggled ON"; else t = "Bit-flag1 is toggled OFF"; } else if ("bit2" == m) { glb_tog = glb_tog ^ lzy_bit2; if (glb_tog & lzy_bit2) t = "Bit-flag2 is toggled ON"; else t = "Bit-flag2 is toggled OFF"; } else if ("bit3" == m) { glb_tog = glb_tog ^ lzy_bit3; if (glb_tog & lzy_bit3) t = "Bit-flag3 is toggled ON"; else t = "Bit-flag3 is toggled OFF"; } else if ("bit4" == m) { glb_tog = glb_tog ^ lzy_bit4; if (glb_tog & lzy_bit4) t = "Bit-flag4 is toggled ON"; else t = "Bit-flag4 is toggled OFF"; } else if ("bit5" == m) { glb_tog = glb_tog ^ lzy_bit5; if (glb_tog & lzy_bit5) t = "Bit-flag5 is toggled ON"; else t = "Bit-flag5 is toggled OFF"; } llOwnerSay(t); t = ""; } } }

EDIT: This page has some good info on bit-flags and masks

Example Snippet (optimized logic style) for intermediate & advanced levels -  Credits go to wherorangi for sharing this:

integer glb_tog;

default
{
    state_entry()
    {
        llListen(2, "", llGetOwner(), "");
    }
    
    listen(integer c, string n, key i, string m)
    {
             
       // expects m to be in the range "0".."4"

        glb_tog = glb_tog ^ (1 << (integer)m);
        
        llOwnerSay( 
            "Bit-flag" + m + " is toggled " + 
            llList2String(["OFF","ON"], (glb_tog >> (integer)m) & 0x1) 
        );
    }
}

EDIT: Add this script to a prim and type in chat "/2 4" or any number without quotes.

Link to comment
Share on other sites

This assembler-like technique may appear totally foreign to hi-level object oriented languages (of which LSL is one) and therefore totally outdated. Yet as surprising as it sounds, it is still in widespread use for such things as BIOS and BSP development, interrupt processing, automotive and other real-time firmware where processing speed is a crucial issue (of course more efficient coding would be used).

SL applications are real-time processing but it is very "soft" real time because frames are sent to the viewer very slowly (computer-wise) at a speed of just 42 per second (about each 24 msec) and latency is not an issue. This considered using such techniques in LSL is really a matter of programmer's preference.

Link to comment
Share on other sites

I'd prefer the term "Old School" rather than outdated but it's just a method that works, and saves the coder or "soft" coder unnecessary "memory tax" (if I can call it that) for things like multiple buttons extending/retracting multiple menus exclusively within a HUD-script that  use only one global integer for all toggles. It's quite simple to understand: If you're just doing simple toggles, then the bit-masks bit-flags need to be certain even numbers that have only ONE binary "1" out of the all the "0"s within: I personally did not know this until last night.

1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 and so on..perfect for YES/NO togglingBinary.....Dec..Hex
00000001 = 1 ...(0x01)00000010 = 2 ...(0x02)00000100 = 4 ...(0x04)00001000 = 8 ...(0x08)00010000 = 16...(0x10)00100000 = 32...(0x20)01000000 = 64...(0x40)10000000 = 128..(0x80)and then double:0000000100000000 = 256 ..(0x100)0000001000000000 = 512 ..(0x200)0000010000000000 = 1024..(0x400)0000100000000000 = 2048..(0x800)So on......
All 1s you see here just happen to be out of each other's way.

Any other numbers like 3 = 00000011 (odd number) is going to toggle it's self and others at the same time using the XOR ^ method (from what I get) and you don't want that for just simple exclusive true/false flipping.

You can (however) toggle odd numbers by method of bit-shifting << or >> to basically "scoot" the 1s in or out of the way.. Assuming I'm correct hehe. I am personally thankful that LSL allows this..

EDIT: Not all even numbers contain single 1's:  6, 10, 12, 14 , 18,  22, etcetera'cetera.....

Link to comment
Share on other sites

Of course not all even numbers contain a single '1' bit... in fact most of them would contain more than one. The test here is if the lowest bit equals one. For even numbers it would always contain a '0' and for odd numbers:  '1'.

And indeed

integer IsEven(integer src) { return !(src & 0x1); }

is much much faster than

integer IsEven(integer src)  { return !(src%2); }

unless the compiler is smart enough to substitute, but LSL compiler is rather dumb.

As for building menus, just use this API I've made it for y'all years ago.

Link to comment
Share on other sites

Bit flags are useful but why restrict the use to the Exclusive OR function when we have the full register?

// bit logic by Dora Gustafson, Studio Dora 2016integer bits; // contains flags 0 thru 31integer flag( integer x){    return 1<<x & bits;}setflag( integer x){    bits = 1<<x | bits;}clrflag( integer x){    bits = ~( 1<<x) & bits;}eorflag( integer x){    bits = 1<<x ^ bits;}showbits(){    string s;    integer i = 32;    while ( i-- )    if ( flag( i)) s+="1";    else s+="0";    llOwnerSay( s);}default{    state_entry()    {        showbits();        setflag( 0);        setflag( 3);        setflag( 4);        showbits();        clrflag( 2);        clrflag( 3);        eorflag( 4);        eorflag( 5);        setflag( 31);        showbits();    }}/*Test output: 00000000000000000000000000000000Test output: 00000000000000000000000000011001Test output: 10000000000000000000000000100001*/

I use bit flags regular but never in a convoluted  form like this, rather as in-line code

:smileysurprised::):smileyvery-happy:

  • Like 1
Link to comment
Share on other sites

/*Test output: 00000000000000000000000000000000Test output: 00000000000000000000000000011001Test output: 10000000000000000000000000100001*/

integer MEGA_ZERO = 0; //Extrapolated: [0000 0000₁ | 0000 0000₂ | 0000 0000₃ | 0000 0000₄]

If I'm correct, that's 4 bytes worth of binary zeros & ones mostly squandered (by ammature coders like myself) since typically 1 out of those 32 bits gets assigned as a boolean, becomes a substantial waste of bitspace even if you have a project that needs like four to eight or even ten togglers.

And the reason why I don't dare petition the Linden-Labers to give us the ability to declare smaller vars like "char", or something  like "integer8", "integer16" (for situations like this), is because that would be asking them to risk breakage on other parts of code functionality unless its on the preview grid.

So this is kind of why its (IMO) better practice to use just "put in" one integer to globally toggle everything especially with a limited size of 64k per script, stuff can add up fast.  After combing the LSL portal, I've noticed there's really not much info/talk about bit-flagging (unless I overlooked something) and I'm pleased that people are starting to support this as good practice for second life and I really think LL should get this wiki'd if its not already.

Link to comment
Share on other sites

This quote from learncpp.com has a good answer for that question ( I think ):

Let’s take a look at a more concrete example. Imagine you're creating game where 
there are monsters for the player to fight. When a monster is created, it may be
resistant to certain types of attacks (chosen at random). The different type of
attacks in the game are: poison, lightning, fire, cold, theft, acid, paralysis,
and blindness.
In order to track which types of attacks the monster is resistant to, we can use
one boolean value per resistance (per monster). that's 8 booleans per monster.With 100 monsters, that would take 800 boolean variables, using 800 bytes of memory.However, using bit flags:1 const unsigned char resistsPoison = 0x01;2 const unsigned char resistsLightning = 0x02;3 const unsigned char resistsFire = 0x04;4 const unsigned char resistsCold = 0x08;5 const unsigned char resistsTheft = 0x10;6 const unsigned char resistsAcid = 0x20;7 const unsigned char resistsParalysis = 0x40;8 const unsigned char resistsBlindness = 0x80;Using bit flags, we only need one byte to store the resistances for a single monster,
plus a one-time setup fee of 8 bytes for the options. With 100 monsters, that would
take 108 bytes total, or approximately 8 times less memory. For most programs, the
amount of memory using bit flags saved is not worth the added complexity. But in
programs where there are tens of thousands or even millions of similar objects,
using bit flags can reduce memory use substantially. it's a useful optimization to
have in your toolkit if you need it.

 This quote talks about single byte chars, not 32 bit LSL integers. So of course if there's only one toggle then only one integer needed, in LSL.

Link to comment
Share on other sites

I'm skeptical of the value of bit-packing. I think the overhead required to do it greatly exceeds the variable space savings.

Read this...

http://wiki.secondlife.com/wiki/LSL_Script_Memory

Global integers are (if I'm reading that page correctly) about 10 bytes long.

To extract a bit requires masking against a constant. Each integer constant takes 6 bytes of memory.

Creating a function to handle booleans packed into integers also takes space. Each function call takes 21 bytes, plus the size of whatever's returned. If that's an integer, I think that's another 10 bytes.

Unless I'm misunderstanding the script memory page, all this extra hassle will eat up tremendous amounts of space while simultaneously making the code less readable.

Don't do it!

Link to comment
Share on other sites

I made a comparison: script1 (with one global integer toggling 5 bit-flags as booleans) vs script2 (with five global integers as booleans; no bit-flags).. Both scripts were compiled with memory checks.

Script1 returned an average total of 7560 bytes while script2 returned an average of 7576 bytes. The difference is not substantial but it does show that bit-flagging (in Second Life) does indeed decrease memory payload rather than increase it.

script1: Bit-flaggedx5

integer glb_tog;
MC() //memcheck{ llSetText("Limited Memory " + (string)llGetMemoryLimit() + "\nUsed Memory " + (string)llGetUsedMemory() + "\nFree Memory " + (string)llGetFreeMemory(), <1,1,1>, 1);}
MCI()// memcheck init{
llScriptProfiler(1); MC(); llScriptProfiler(0); llOwnerSay("This script used at most " + (string)llGetSPMaxMemory() + " bytes of memory during Test."); } default{ state_entry() { llListen(22,"",NULL_KEY,""); MCI(); } listen(integer c, string n, key i, string m) { key r = llGetOwnerKey(i); key x = llGetOwner(); if (r != x) return; else { string t; if ("bit1" == m) { glb_tog = glb_tog ^ 0x01; if (glb_tog & 0x01) t = "Bit-flag1 is toggled ON"; else t = "Bit-flag1 is toggled OFF"; } else if ("bit2" == m) { glb_tog = glb_tog ^ 0x02; if (glb_tog & 0x02) t = "Bit-flag2 is toggled ON"; else t = "Bit-flag2 is toggled OFF"; } else if ("bit3" == m) { glb_tog = glb_tog ^ 0x04; if (glb_tog & 0x04) t = "Bit-flag3 is toggled ON"; else t = "Bit-flag3 is toggled OFF"; } else if ("bit4" == m) { glb_tog = glb_tog ^ 0x08; if (glb_tog & 0x08) t = "Bit-flag4 is toggled ON"; else t = "Bit-flag4 is toggled OFF"; } else if ("bit5" == m) { glb_tog = glb_tog ^ 0x10; if (glb_tog & 0x10) t = "Bit-flag5 is toggled ON"; else t = "Bit-flag5 is toggled OFF"; } llOwnerSay(t); t = ""; } }}

script2:  global integers x5:

integer glb_tog1;integer glb_tog2;integer glb_tog3;integer glb_tog4;integer glb_tog5;MC()// memcheck{    llSetText("Limited Memory " + (string)llGetMemoryLimit() +              "\nUsed Memory "  + (string)llGetUsedMemory()  +              "\nFree Memory "  + (string)llGetFreeMemory(), <1,1,1>, 1);}
MCI()// memcheck init{ llScriptProfiler(1); MC(); llScriptProfiler(0); llOwnerSay("This script used at most " + (string)llGetSPMaxMemory() + " bytes of memory during Test."); } default{ state_entry() { llListen(22,"",NULL_KEY,""); MCI(); } listen(integer c, string n, key i, string m) { key r = llGetOwnerKey(i); key x = llGetOwner(); if (r != x) return; else { string t; if ("bit1" == m) { glb_tog1 =! glb_tog1; if (glb_tog1) t = "Bit_flag1 is toggled ON"; else t = "Bit_flag1 is toggled OFF"; } else if ("bit2" == m) { glb_tog2 =! glb_tog2; if (glb_tog2) t = "Bit_flag2 is toggled ON"; else t = "Bit_flag2 is toggled OFF"; } else if ("bit3" == m) { glb_tog3 =! glb_tog3; if (glb_tog3) t = "Bit_flag3 is toggled ON"; else t = "Bit_flag3 is toggled OFF"; } else if ("bit4" == m) { glb_tog4 =! glb_tog4; if (glb_tog4) t = "Bit_flag4 is toggled ON"; else t = "Bit_flag4 is toggled OFF"; } else if ("bit5" == m) { glb_tog5 =! glb_tog5; if (glb_tog5) t = "Bit_flag5 is toggled ON"; else t = "Bit_flag5 is toggled OFF"; } llOwnerSay(t); t = ""; } }} 

 EDIT: If you notice that script2 still shows the string literals with Bit-flags quoted, I left those alone because this test is not comparing string size but rather the integers vs the actual bit-flags, incase anyone's wondering.

Link to comment
Share on other sites

Malinda am not picking on you ok. Or on Maddy either. bc you both right in your own ways

i just think that is important to add to the convo given our readership on this scripting forum and why people come here

+

learning how to use bitwise in our apps is well worth learning. There are times when this is really useful. Particularly when we start getting into logic programming constructs

i give a snip example of logic programming using the tests scripts as a comparative

 

integer glb_tog;default{    state_entry()    {        llListen(2, "", llGetOwner(), "");    }        listen(integer c, string n, key i, string m)    {                    // expects m to be in the range "0".."4"        glb_tog = glb_tog ^ (1 << (integer)m);                llOwnerSay(             "Bit-flag" + m + " is toggled " +             llList2String(["OFF","ON"], (glb_tog >> (integer)m) & 0x1)         );    }}

+

is when we use logic programming in conjunction with relational bitwise storage that we start to get worthwhile gains

when using imperative programming constructs (which most non-professional LSL/VB/C#/JS/etc scripters do use) then the benefits of bitwise storage for its own sake is pretty marginal. And can often reduce the readabilty of imperative programming codes considerably. Which confuses the junior coders and drives the seniors nuts (:

the seniors go nuts bc we are mixing our imperatives in with our logics and functionals for no good reason at worst and marginal benefit at best, and the resulting mess of code often shows this. Cue Maddy in here (:

+

i suggest to anyone reading (who doesnt know already) to study up on and try grow your skills beyond imperative programming into both logic and functional programming

when used appropriately the rewards of this can be quite considerable in the LSL runtime environment

 

  • Like 1
Link to comment
Share on other sites

Bit flag parameters are used in many LSL functions and not in a small way

  1. llTakeControls() and control
  2. llRequestPermissions() and run_time_permissions
  3. llGetInventoryPermMask and llGetObjectPermMask()
  4. Masks in llParticleSystem()
  5. llSetVehicleFlags and llRemoveVehicleFlags

I will not list them all

These examples shows what bit flags are good at: Marking and unmarking mutual independent cases

:smileysurprised::):smileyvery-happy:

Link to comment
Share on other sites


Dora Gustafson wrote:

Bit flag parameters are used in many LSL functions and not in a small way
  1. and
  2.  and
  3. and
  4. Masks in
  5. and

I will not list them all

These examples shows what bit flags are good at: Marking and unmarking mutual independent cases

:smileysurprised:
:)
:smileyvery-happy:

Bit manipulation absolutely has its uses. It would be impossible to control computer hardware without it, as the CPU control and peripheral interfaces registers are comprised of various bits that do things. And when calling functions that take and return bit-packed arguments, you have no choice but to provide and parse them. Many languages have bit-field variables that handle this directly, making code more reliable and easier to write error-free. LSL isn't one of them ;-).

The cost of bit packing and unpacking has motivated some chip manufacturers to redesign the addressing of bits in control registers to avoid the need to pack and unpack them. They might provide three registers, one for direct access, one for setting bits, one for clearing. Or they might spread a 32 bit control register across 32 addresses, with each address containing only one bit. And they might provide a 33rd address that contains all 32 bits of that control register in one place for rapid initialization. There's more than enough address space in modern computers to allow these approaches.

My argument is that you mustn't just presume that, because you can pack 32 one-bit flags into an integer, that you've saved space (or execution time, which can also be important). It's important to understand the environment in which your code will run.

Link to comment
Share on other sites


wherorangi wrote:

Malinda am not picking on you ok. Or on Maddy either. bc you both right in your own ways

i just think that is important to add to the convo given our readership on this scripting forum and why people come here

+

learning how to use bitwise in our apps is well worth learning. There are times when this is really useful. Particularly when we start getting into logic programming constructs

i give a snip example of logic programming using the tests scripts as a comparative

 
integer glb_tog;default{    state_entry()    {        llListen(2, "", llGetOwner(), "");    }        listen(integer c, string n, key i, string m)    {                    // expects m to be in the range "0".."4"        glb_tog = glb_tog ^ (1 << (integer)m);                llOwnerSay(             "Bit-flag" + m + " is toggled " +             llList2String(["OFF","ON"], (glb_tog >> (integer)m) & 0x1)         );    }}

+

is when we use logic programming in conjunction with relational bitwise storage that we start to get worthwhile gains

when using imperative programming constructs (which most non-professional LSL/VB/C#/JS/etc scripters do use) then the benefits of bitwise storage for its own sake is pretty marginal. And can often reduce the readabilty of imperative programming codes considerably. Which confuses the junior coders and drives the seniors nuts (:

the seniors go nuts bc we are mixing our imperatives in with our logics and functionals for no good reason at worst and marginal benefit at best, and the resulting mess of code often shows this. Cue Maddy in here (:

+

i suggest to anyone reading (who doesnt know already) to study up on and try grow your skills beyond imperative programming into both logic and functional programming

when used appropriately the rewards of this can be quite considerable in the LSL runtime environment

 

My "don't do it" might have been a li'l dramatic, but given the test Melinda did on bit packing vs not, I'd still not do it. I don't think the slight cost savings justifies the loss of readability, and there may be no situation where it does. In other contexts the choice may be very clear or of no consequence.

My point is similar to yours (though it comes from a different background). It is absolutely valuable to know how to manipulate bits. There are circumstances where you can't avoid it (as Dora illustrated). But in situations where you are free to choose, you should step back and look at the big picture. There will be tradeoffs in size, speed, readability and reliability and the relative value of each.

And when senior coders go nuts over the doings of juniors, it's sometimes because they have different perceptions of what's important. And it can be difficult to find fault in ether perception.

This does not apply only to programming.

;-).

 

Link to comment
Share on other sites

That's a very awesome contribution you shared, a bit advanced (EDIT: No pun intended) compared to my "basic script for intermediate and beginners" but nice and compact and it doesn't seem to have a limit and what numbers you can add in either. And that's the magic of tossing in a contribution: It just eventually comes back completely optimized by those willing to spend the time to do so, and I thank you for this. BTW your snippet returned a byte count of 6504. Much-much lower; I'm "jelly'fied!"

integer glb_tog;
MC()//Based on http://wiki.secondlife.com/wiki/LlSetMemoryLimit{ llSetText("Limited Memory " + (string)llGetMemoryLimit() + "\nUsed Memory " + (string)llGetUsedMemory() + "\nFree Memory " + (string)llGetFreeMemory(), <1,1,1>, 1);}MCI(){ llScriptProfiler(1); MC(); llScriptProfiler(0); llOwnerSay("This script used at most " + (string)llGetSPMaxMemory() + " bytes of memory during Test."); }default{ state_entry() { llListen(2, "", llGetOwner(), ""); MCI(); } listen(integer c, string n, key i, string m) { glb_tog = glb_tog ^ (1 << (integer)m); llOwnerSay( "Bit-flag" + m + " is toggled " + llList2String(["OFF","ON"], (glb_tog >> (integer)m) & 0x1) ); }}

I think that LL should add yours to the portal minus the bloated benchmark code I added..

 

Link to comment
Share on other sites

I don't think you can save space, since you need some extra code to operate the bitfields.

I use them sometimes since i can easily set, delete, flip or compare single or multiple flags in a single operation. And it's pretty easy to loop through a bitfield. Alot easier than using a list by my taste.

So I use bitfields when I think it makes sense but never to save space.

Link to comment
Share on other sites

It is absolutely valuable to know how to manipulate bits. There are circumstances where you 

can't avoid it (as Dora illustrated). But in situations where you are free to choose, you

should step back and look at the big picture. There will be tradeoffs in size, speed,

readability and reliability and the relative value of each.

Just so everyone know's I'm strictly talking about toggling bits only. Err.. we are talking about toggling bits right?

Madelaine is correct that the differences in size basically: does not constitute an alarm for all of us to recall our best selling products off the marketplace just to get a less than 10 percent reduction in size, but it does make sense to use this practice of bit-flagging in new projects to come. So now the argument that I present to everyone is: What's the best way of doing it?

From what I've seen with LSL scripting, when it comes to toggling bits, there is no adverse tradeoff of speed, size or readability from the bits alone by either XOR or shifting. That would just depend of how the overall script itself is written. I mean, I already know that my basic snippet, with its ugly and redundant nested "else if" flow is not the most optimal way. Advanced coders (both soft and hard) would look at it and laugh.

I didn't start this topic to try and "preach to the choir". There are tons of higly skilled coders here, but some of us just don't know bits and I believe that a basic understanding is needed for some of us amateur folk. So I thought I'd try to explain it as elementary as I could and I hope nobody took it as condescension either. If so? My apologies..

 

Link to comment
Share on other sites

since you need some extra code to operate the bitfields.

Yes and no; allow me to explain:

Yes:  When adding say.. bit "0x01" literally and directly into it's own conditional scope will add bytes but you're actually using less because,

No:  That as long as you DON'T declare "0x01" as an integer itself in global, the overall byte count will not exceed as compared to globally declaring it, would of course add an additional 10 bytes. In the long run you'd get a bloated byte count, defeating the purpose of saving space. Adding mulitple global variables as exclusive toggles (especially if they're 32 bit ints) are allot more heavier in bytes overall as compared to just one 32 bit global toggle being XOR'd against an array of literal bit entries.

See the benchmarks I posted. If you look at my comparison, you will notice the difference in size that using bit-flags compared to global integers came out on top.

This is why I love Firestorm and it's "Lazy List" feature because making lazy defines allow you to give your "literal value" a title as you would with a global but without it lingering in global memory. All "lazy listing" does is tell the compiler to replace the title with the macro defined value right where it belongs: directly in its scope saving byte space..

EDIT TL;DR: Rule of thumb is: In LSL you can declare a global integer but never declare it's bit globally.

Link to comment
Share on other sites


Malinda Quartz wrote:

but given the test Melinda did on bit packing vs not, I'd still not do it.

My apologies but that has got to be the most baffling thing I've ever read. You'd still "not" do it even though the benchmarks clearly showed bit-flagging > integer toggling? GOOD LORDEH!

EDIT bit-"flagging" not "packing"

Yes. Your benchmark showed a 0.2% (16 byte out of 7600) reduction in code size. I don't think that savings is worth the reduction in readability/understandability.

I'm not knocking the method, it's valuable to know and there may be a place in LSL where the advantage is clear.

Link to comment
Share on other sites

Hey hey now, that's cool; I don't want any trouble. I didn't mean to insult you or your circle of friends. I mean if you wanna turn down a 0.2% increase in available space. Hey, that's your right. I yeild..

I mean why the heck would I accept a trivial 10℄ hourly raise in my paycheck, right? I'm better than that., you know? In fact that'd piss me off! So much, I wouldn't care of the fact that crap would add up to lousy 80℄ a day. Heck why would I care if that 80℄ totaled out to a measally $4 pathetic dollars a week, or $20 a month!  $240a year, eh?

thats what I'm saying?

You all can correct me on the math here but come on.. That's not the point. "sheeesh!"

EDIT math booboo fixed

Link to comment
Share on other sites


Malinda Quartz wrote:

"jelly'fied!"

 

(:

dont worry about it

the good thing is that in raising this topic you started a discussion, to which others (incl. myself) have been able to contribute

and also shows that you are on a journey of discovery advancing your knowledge and skills as you go. Thats really good. The willingness to undertake that journey and to also share what you are discovering along the way

and for sure in undertaking journeys then we can get shoulder bumped sometimes to help point us in a direction we can think about taking

i get shoulder bumped quite a lot myself on all kinda stuffs. And is all good. And if I ever did know everything about everything then I wouldnt have anything much to talk about (:

+

ps

i got jelly'fied the other day on another thread on another topic on here . Was like: oh! man! I am so jelly about that

but now I know what I never knew before about that. So now I get to have jelly as well as icecream for pudding (:  

(:

Link to comment
Share on other sites


Malinda Quartz wrote:

Hey hey now, that's cool; I don't want any trouble. I didn't mean to insult you or your circle of friends. I mean if you wanna turn down a 0.2% increase in available space. Hey, that's your right. I yeild..

I mean why the heck would I accept a trivial 10℄ raise in my paycheck, right? I'm better than that., you know? In fact that'd piss me off! So much, I wouldn't care of the fact that crap would add up to lousy 80℄ a day. Heck why would I care if that 80℄ totaled out to a measally $4 pathetic dollars a week, or $10 a month!  $120 a year, eh?

You get what I'm saying?

You all can correct me on the math here but come on.. That's not the point. "sheeesh!"

EDIT math booboo fixed

I don't feel insulted, Malinda. And I hope you don't either. I'm simply stating that for me personally, there is value in writing code that's easy to understand and reduces the potential for error. One of the reasons I was reasonably successful in my career is that I took care to make sure that my code worked, but also that those who followed me would understand it, maintain it, and improve upon it.

Think carefully about your analogy to wages. How much extra time might it take to implement bit-packing/flagging rather than simply declaring variables as needed? If you get paid by the script, would it be more efficient to "waste" a few bytes than a few minutes

The thrill of learning a new method can easily be its own reward, and it's wonderful if that's what's motivating you. These are the kinds of tradeoffs everybody must make, whether writing code or doing anything else. I can no longer experience this particular thrill, so I must find mine elsewhere, where someone may look at me and roll their eyes.

Link to comment
Share on other sites


Malinda Quartz wrote:

 

Credits go to wherorangi for sharing this:
[some code snippet]

.

i dont need to be credited for anything I post on these forums

pretty much everything I do post is a LSL port of something which is a standard practice in any coding workshop, and can be found in pretty much any textbook and/or tutorial

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 2772 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...