Hex
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
Function: string hex(integer value);
Returns the hexadecimal nybbles of the signed integer value in order. Specifically returns the nybbles from most to least significant, starting with the first nonzero nybble, folding every nybble to lower case, and beginning with the nonnegative prefix "0x" or the negative prefix "-0x".
Parameters:
• integer | value | – | signed value to be expressed as signed hex |
Note: Results with eight nybbles begin always with one of the positive signed nybbles 1 2 3 4 5 6 7, never with a zero or unsigned nybble 0 8 9 A B C D E F.
Caution: This page was a work in progress as of 2007-10. The specification, the implementations, the demo, and the sample results may not yet be totally consistent. See the discussion tab.
Implementations
Easy To Use, and Correct At A Glance
You should find this implementation feels easy to call and modify and review. For example, you could substitute the easy-to-read upper case A B C D E F nybbles of IBM style for the easy-to-type lower case a b c d e f nybbles of AT&T style. Please consider sharing your experience in the discussion tab.
// http://wiki.secondlife.com/wiki/hex string XDIGITS = "0123456789abcdef"; // could be "0123456789ABCDEF" string bits2nybbles(integer bits) { string nybbles = ""; while (bits) { integer lsbs = (bits & 0xF); string nybble = llGetSubString(XDIGITS, lsbs, lsbs); nybbles = nybble + nybbles; bits = bits >> 4; // discard the least significant bits at right bits = bits & 0xfffFFFF; // discard the sign bits at left } return nybbles; } string hex(integer value) { if (value < 0) { return "-0x" + bits2nybbles(-value); } else if (value == 0) { return "0x0"; // bits2nybbles(value) == "" when (value == 0) } else // if (0 < value) { return "0x" + bits2nybbles(value); } }
Fast
You should agree this implementation feels like it could run fast in 2007 SL before Mono. Please consider contributing measures of how much faster/ smaller this code is to the discussion tab.
// http://wiki.secondlife.com/wiki/hex string XDIGITS = "0123456789abcdef"; // could be "0123456789ABCDEF" string hexu(integer bits) { integer lsbs = (bits & 0xF); string nybbles = llGetSubString(XDIGITS, lsbs, lsbs); if ((bits = (0xfffFFFF & (bits >> 4)))) { do { nybbles = llGetSubString(XDIGITS, lsbs = (bits & 0xF), lsbs) + nybbles; } while ((bits = (bits >> 4))); } return "0x" + nybbles; } string hex(integer value) { if (value < 0) return "-" + hexu(-value); return hexu(value); }
Small
Reworked version of fast code. Not as fast on the loop but less bytecode.
// http://wiki.secondlife.com/wiki/hex string hexu(integer bits) { integer lsbs = (integer)"";//saves 1 byte over using zero but is SLOW string nybbles = ""; do nybbles = llGetSubString("0123456789abcdef", lsbs = (bits & 0xF), lsbs) + nybbles; while ((bits = (0xfffFFFF & (bits >> 4)))); return "0x" + nybbles; } string hex(integer value) { //saves one byte over "value < 0" and is faster. if (value & 0x80000000) return "-" + hexu(-value); return hexu(value); }
Demo
Show the most astonishing test cases for the hex function and then also the permission masks of the script running to demo the hex function.
Code:
default { state_entry() { llOwnerSay("Hello"); llOwnerSay(hex(0) + " == 0"); llOwnerSay(hex(0x00FEDC00 & -0x00FEDC00) + " == (0x00FEDC00 & -0x00FEDC00)"); llOwnerSay(hex(1 << 30) + " == (1 << 30)"); llOwnerSay(hex(0x80000000) + " == 0x80000000"); llOwnerSay(hex(0xFEDC9876) + " == 0xFEDC9876"); llOwnerSay(hex(-1) + " == -1"); llOwnerSay(hex(0x123456789) + " == 0x123456789"); llOwnerSay("OK"); llOwnerSay("Hello again"); string item = llGetScriptName(); llOwnerSay(hex(llGetInventoryPermMask(item, MASK_BASE)) + " as base"); llOwnerSay(hex(llGetInventoryPermMask(item, MASK_OWNER)) + " by owner"); llOwnerSay(hex(llGetInventoryPermMask(item, MASK_GROUP)) + " by group"); llOwnerSay(hex(llGetInventoryPermMask(item, MASK_EVERYONE)) + " by anyone"); llOwnerSay(hex(llGetInventoryPermMask(item, MASK_NEXT)) + " by next owner"); llOwnerSay("aka " + (string) llGetInventoryPermMask(item, MASK_NEXT)); llOwnerSay("OK"); } }
Sample Results:
Hello 0x0 == 0 0x400 == (0x00FEDC00 & -0x00FEDC00) 0x40000000 == (1 << 30) -0x80000000 == 0x80000000 -0x123678a == 0xFEDC9876 -0x1 == -1 -0x1 == 0x123456789 OK Hello again 0x7fffffff as base 0x7fffffff by owner 0x0 by group 0x0 by anyone 0x82000 by next owner aka 532480 OK
Design Rationale
Why These Implementations
These implementations reproduce how hex integer literals often appear in LSL script, conforming to such arbitrary and traditional AT&T C conventions as:
- return lower case a b c d e f rather than upper case A B C D E F,
- return a signed 31-bit result if negative, rather than an unsigned 32-bit result,
- omit the leading quads of zeroed bits, except returns "0x0" rather than "0x" when the result is zero,
- return a meaningless "0" before the "x", as LSL and C compilers require,
- return the "x" on the left as in LSL and C, not the "h" on the right as in Assembly code, and
- return the nybbles listed from most to least significant as in English, not listed from least to most significant as in Arabic.
Why Python Hex Relevant
Our implementations produce exactly the same results as the hex function of the Python scripting language.
Brief doc for the Python hex function appears buried deep within http://docs.python.org/lib/built-in-funcs.html
Disputes over the detailed specification of the Python hex function appear buried deep within http://www.python.org/dev/peps/pep-0237/
Why Multiple Implementations
We programmers divide into schools by our passionately held personal aesthetics, just like other poets. Not everyone here agrees exactly on the relative measures and importance of such fuzzy source code qualities as:
- easy to use
- correct at a glance
- small
- fast
As you read this page, you have to wade thru more than one implementation only because not all our community yet agrees that the only code you wish to see is the code from my school.