Core Function Vec

From Sputnik Wiki
Jump to: navigation, search
Vec( <expression>, <offset>, <bits> )
Vec( <expression>, <offset>, <bits> ) = <value>
Vec( <expression>, <offset>, <bits> )++
Vec( <expression>, <offset>, <bits> ) +=<value>
...
...
...

Contents

Description

Treats the binary variable in EXPRESSION as a bit vector made up of elements of width bits and returns the value of the element specified by OFFSET as an unsigned integer and optionally sets BITS in the binary variable to a given value.

BITS therefore specifies the number of bits that are reserved for each element in the bit vector. This must from 1 to 64 however if it ranges from higher than 8 it must be in a power of two (below 8 does not have this limit).

If BITS is 8, "elements" coincide with bytes of the input binary variable.

If BITS is 16 or more, bytes of the input binary variable are grouped into chunks of size BITS/8, and each group is converted to a number as with pack()/unpack() with big-endian formats n /N (and analogously for BITS==64). See pack for details.

If bits is 4 or less, the binary variable is broken into bytes, then the bits of each byte are broken into 8/BITS groups.

Bits of a byte are numbered in a little-endian-ish way, as in 0x01 , 0x02 , 0x04 , 0x08 , 0x10 , 0x20 , 0x40 , 0x80.

For example, breaking the single input byte chr(0x36) into two groups gives a list (0x6, 0x3) ; breaking it into 4 groups gives (0x2, 0x1, 0x3, 0x0) .

vec may also be assigned to, by using the value parameter example:

vec($image, $max_x * $x + $y, 8) = 3; // Settting value 3

If the selected element is outside the binary variable, the value 0 is returned. If an element off the end of the binary variable is written to, Spunik will first extend the binary variable with sufficiently many zero bytes. It is an error to try to write off the beginning of the binary variable (i.e., negative OFFSET).

Binary variables created with vec can also be manipulated with the logical operators |, & , ^, and ~ .

These operators will assume a bit vector operation is desired when both operands are binary variables.

Parameters

binary-array

The binary variable to use.

This should be a variable so it can be written to and stored.

The binary variable will be increased in size as you demand so in the OFFSET.

The binary variable will be MODIFIED IN PLACE (as a byte* internally) and is not reconstructed at each edit this provides maximal speed the only time this does not apply is if you are resizing the binary variable then it has no choice but to copy it.

You can also preallocate the binary variable a given length (See examples for how to).

offset

Offset is the marker for the end of the vector, and it counts back the number of bits specified to find the start.

Unlike in Perl you may use a Negative offset and it will cause the operation to take place that many characters from the end of the binary variable.

bits

BITS specifies the number of bits that are reserved for each element in the bit vector.

This must be a power of two IF the number is from 8 to 64 however numbers BELOW 8 are not required to be a power of two.

value

Optional; A numeric value to set to the Vec().

If it is a floating point it will be rounded.

If it is a string or anything else it will be converted to an Integer (Int64).

If it is a Binary variable Vec() will try convert it to an integer of up to Int64 size (Any bytes in excess of 8 will be ignored).

The return value still takes effect even you set a value to the Vec().

Return Value

This function returns the value of the bit field specified by OFFSET.

You must use Vec() if you wish to edit the binary variable at the offset and bits you can't use the return value from a Vec() and expect to edit it hoping to change the binary variable this will fail.

You can't use the return value to modify the binary variable.

Remarks

This function is inspired by Perl's Vec() function and any tutorial you find for Perl one that should work on this.

This function is smart enough to know if it should increase the binary variables size or not therefor it will return/edit the parts of the binary variable you wish to without rebuilding the binary variable each time this is significantly faster than recreating the binary variable every time.

In Sputnik binary variable are not immutable. For most operations a binary variable will be modified in place and the Vec() also modifies binary variables in place.

A Vec() has to be on the left side of an operation for it to get SET such as otherwise you can only GET from it.

Technically the Vec() is not a function like most others it's actually more of a language feature similar to an If statement so if you enter wrong number of parameters you will be notified instantly even before execution of your script begins. Since it is a language feature rather than a generic function its structure is parsed literally.

To display a Vec()'s binary variable as a string you can cast it as a (string) like (string)$vec however that is ASCII only if you wish to use Unicode you must use the BinaryToStr() function

Vec() is often used when dealing with sockets since it very good at reading and creating all kinds of headers etc.

Example

Bits example

my $vec = null;
vec($vec,  3, 4) = 1;  # bits 0 to 3
vec($vec,  7, 4) = 10; # bits 4 to 7
vec($vec, 11, 4) = 3;  # bits 8 to 11
vec($vec, 15, 4) = 15; # bits 12 to 15
# As there are 4 bits per number this can
# be decoded by unpack() as a hex number
my $hex = UnpackSingle("h*", $vec);
print("vec() Has a created a string of nybbles, in hex: $hex\n");
// PRINTS:
// vec() Has a created a string of nybbles, in hex: 0001000A0003000F

Example of packing two floating point numbers into a bit vector then retrieving them later

my $foo = null;
vec($foo, 0, 32) = Pack("f", 133.7);
vec($foo, 1, 32) = Pack("f", 777.42);
# This works because Vec() will read the binary array similar to how
# Unpack() would read it with with C s i q format Vec() will choose
# what it thinks is the correct format to read based on how big the
# binary array is and it will pad 0 bytes to the end if its off like
# 3 bytes or 7 bytes etc.
 
say "\$foo is '$foo'";
#$foo is 'C♣³3DBZá'
 
say "First float is: " . Unpack("f", vec($foo, 0, 32), 3);
#First float is: 133.7
 
say "Second float is: " . Unpack("f", vec($foo, 1, 32), 3);
#Second float is: 777.42

Print a bit vector

my $foo = null;
vec($foo, 0, 64) = 0x537075746E696B00;
printf "\$foo is: %s\n", (string)$foo;
# $foo is: Sputnik
printr $foo;
# {BINARY:8}
# {
#         [0] => 83
#         [1] => 112
#         [2] => 117
#         [3] => 116
#         [4] => 110
#         [5] => 105
#         [6] => 107
#         [7] => 0
# }

Binary and Vec vectors are the same thing

// Create a binary variable
$vec = Pack("A*", "Zputnik");
 
// Edit the first character
vec($vec, 0, 8) = @'S';
 
// Add a period to the end
vec($vec, strlen($vec), 8) = @'.';
 
say $vec; # Sputnik.

Looking for a way to spawn a binary variable of a specific size to be used as a Vec()?

# Vec() can work on an empty binary variable just fine
# it will increase the binary variables size as it needs to
# there is no need to ever preallocate the binary variable.
 
# However if you find you want to then this is how to.
 
# So a 100 byte long binary variable is same as
$vec = BinaryCreate(100, @'T'); # Make a binary variable 100 bytes long filled with 'T' chars
$vec = BinaryCreate(100, @'A'); # Make a binary variable 50 bytes long filled with 'A' chars
$vec = StrNew(100, @' '); # Make a binary variable 50 bytes long filled with ' ' (space) chars
$vec = BinaryCreate(100, 0); # Make a binary variable 50 bytes long filled with null chars (0x00 null byte)
$vec = BinaryCreate(100, 077); # Use Octal to define the byte for the new binary variable to be filled with
$vec = BinaryCreate(100, 0x31); # Use Hex to define the byte for the new binary variable to be filled with
$vec = BinaryCreate(100, 65); # Use Decimal to define the byte for the new binary variable to be filled with
 
# Once you have created the binart variable of the size you need
# you can begin using Vec() on it example
 
# Pre-allocate the binart variable
$vec = BinaryCreate(10, @'-');
say (string)$vec; # ----------
vec($vec, 0, 8) = @'S'; # Use @'' which is the Sputnik CharLiteral
vec($vec, 1, 8) = @'P'; # It would be a bad idea to just use '' since that is a string!
vec($vec, 2, 8) = @'U';
vec($vec, 3, 8) = @'T';
vec($vec, 4, 8) = @'N';
vec($vec, 5, 8) = @'I';
vec($vec, 6, 8) = @'K';
say (string)$vec; # SPUTNIK---

One often undocumented feature of the Vec() is its ability to use Operators such as ++ example:

my $foo = null;
vec($foo, 0, 32) = 0x5065726C; # 'Perl'
echo "Vec: $foo\n"; # Perl
vec($foo, 1, 8)++; // Increase the second char in the binary variable
echo "Vec: $foo\n"; # Pfrl
vec($foo, 0, 8)++; // Increase the first char in the binary variable
echo "Vec: $foo\n"; # Qfrl
vec($foo, 2, 8) += 4; // Increase the third char in the binary variable by 4
echo "Vec: $foo\n"; # Qfvl
vec($foo, 0, 8) -= vec($foo, 1, 8); // Sub the second char from first
echo "Vec: $foo\n"; # ëfvl
vec($foo, 0, 8) ^= @'A'; // Do a Xor operation
echo "Vec: $foo\n"; # ªfvl
 
# Note that .= and ..= work differently on Vectors so
vec($foo, 0, 8) .= 10; // Is equal to += 10
vec($foo, 0, 8) ..= 10; // Is equal to -= 10

The following code will build up an ASCII (in binary format) saying 'PerlPerlPerl' . The comments show the string after each step. Note that this code works in the same way on big-endian or little-endian machines.

my $foo = null;
vec($foo, 0, 32) = 0x5065726C; # 'Perl'
# $foo eq "Perl" eq "\x50\x65\x72\x6C", 32 bits
printf "Char '%1^c' Byte '%1^d'\n", vec($foo, 0, 8); # prints 80 == 0x50 == ord('P')
vec($foo, 2, 16) = 0x5065; # 'PerlPe'
vec($foo, 3, 16) = 0x726C; # 'PerlPerl'
vec($foo, 8, 8) = 0x50; # 'PerlPerlP'
vec($foo, 9, 8) = 0x65; # 'PerlPerlPe'
vec($foo, 20, 4) = 2; # 'PerlPerlPe' . "\x02"
vec($foo, 21, 4) = 7; # 'PerlPerlPer'
# 'r' is "\x72"
vec($foo, 45, 2) = 3; # 'PerlPerlPer' . "\x0c"
vec($foo, 93, 1) = 1; # 'PerlPerlPer' . "\x2c"
vec($foo, 94, 1) = 1; # 'PerlPerlPerl'
# 'l' is "\x6c"
printf "\$foo is '%s'\n", (string)$foo;
// Prints
// $foo is 'PerlPerlPerl'
 
// Lets replace the middle Perl with Lrep
vec($foo, 1, 32) = 0x4C726570; # 'Lrep'
printf "\$foo is '%s'\n", (string)$foo;
// $foo is 'PerlLrepPerl'

The following code will build up an ASCII (in binary format) saying 'Sputnik' (using 32-Bits)

my $foo = null;
vec($foo, 0, 32) = 0x53707574; # 'Sput'
vec($foo, 1, 32) = 0x6E696B00; # 'nik'
printf "\$foo is: %s\n", (string)$foo;
// $foo is: Sputnik

The following code will build up an ASCII (in binary format) saying 'Sputnik' (using 64-Bits)

my $foo = null;
vec($foo, 0, 64) = 0x537075746E696B00;
printf "\$foo is: %s\n", (string)$foo;
// $foo is: Sputnik

To transform a bit vector into a list of 0's and 1's, use these:

my $foo = null;
vec($foo, 0, 32) = 0x5065726C; # 'Perl'
 
$bits = unpack("b*", $foo, true);
print "$bits\n"; // Prints: 00001010101001100100111000110110
 
// To get each individual bit
foreach(unpack("b*", $foo, true) as $b)
{
	echo "Bit '$b'\n";
}
// Prints
// Bit '0'
// Bit '0'
// Bit '0'
// Bit '0'
// Bit '1'
// Bit '0'
// Bit '1'
// Bit '0'
// Bit '1'
// Bit '0'
// Bit '1'
// Bit '0'
// Bit '0'
// Bit '1'
// Bit '1'
// Bit '0'
// Bit '0'
// Bit '1'
// Bit '0'
// Bit '0'
// Bit '1'
// Bit '1'
// Bit '1'
// Bit '0'
// Bit '0'
// Bit '0'
// Bit '1'
// Bit '1'
// Bit '0'
// Bit '1'
// Bit '1'
// Bit '0'

Using a bit vector to find prime numbers

$MAX = 1000;
 
my $sieve = null;
vec($sieve, $MAX, 1) = 0;
$sieve = ~$sieve;
 
for (my $i = 2; $i <= sqrt($MAX); $i++)
{
	if(!vec($sieve, $i, 1))
		continue;
	for (my $x = $i * 2; $x <= $MAX; $x += $i)
		vec($sieve, $x, 1) = 0;
}
 
for (2 .. $MAX)
{
	print "$_\n" if(vec($sieve, $_, 1));
}
# Prints
# 2
# 3
# 5
# 7
# 11
# 13
# 17
# 19
# 23
# 29
# 31
# 37
# 41
# 43
# 47
# 53
# 59
# 61
# 67
# 71
# 73
# 79
# 83
# 89
# 97
...
...

Are you wondering how to place Floating points into a Vec()? Here is how

// Convert a Float to an Integer (32-bits)
Function FpuToInt($value)
{
	return UnpackSingle('i', PackSingle('f', $value));
}
// Convert a Integer to an Float (32-bits)
Function IntToFpu($value)
{
	return UnpackSingle('f', PackSingle('i', $value));
}
 
// Now we get started
 
// Create a variable to hold the Vec
// NULL is fine since it at least created
// the variable
my $vec = null;
// Add some floating points to the vec
Vec($vec, 0, 32) = FpuToInt(133.42);
Vec($vec, 1, 32) = FpuToInt(777.42);
Vec($vec, 2, 32) = FpuToInt(@PI);
Vec($vec, 3, 32) = FpuToInt(@FloatMax);
 
// Read the floating points from the vec
say IntToFpu(Vec($vec, 0, 32));
say IntToFpu(Vec($vec, 1, 32));
say IntToFpu(Vec($vec, 2, 32));
say IntToFpu(Vec($vec, 3, 32));
 
// PRINTS:
// 133.42
// 777.42
// 3.141593
// 3.402823E+38

Same as above but this time for double precision floating points

// First we define some helper functions
 
// Convert a Float to an Integer (64-bits)
Function FpuDToInt($value)
{
	return UnpackSingle('q', PackSingle('d', $value));
}
// Convert a Integer to an Float (64-bits)
Function IntToFpuD($value)
{
	return UnpackSingle('d', PackSingle('q', $value));
}
 
// Now we get started
 
// Create a variable to hold the Vec
// NULL is fine since it at least created
// the variable
my $vec = null;
// Add some floating points to the vec
Vec($vec, 0, 64) = FpuDToInt(133.42);
Vec($vec, 1, 64) = FpuDToInt(777.42);
Vec($vec, 2, 64) = FpuDToInt(@PI);
Vec($vec, 3, 64) = FpuDToInt(@DoubleMax);
 
// Read the floating points from the vec
say IntToFpuD(Vec($vec, 0, 64));
say IntToFpuD(Vec($vec, 1, 64));
say IntToFpuD(Vec($vec, 2, 64));
say IntToFpuD(Vec($vec, 3, 64));
 
// PRINTS:
// 133.42
// 777.42
// 3.14159265358979
// 1.79769313486232E+308

Example of using a bit value lower than 8 to set the bits instead of bytes

// Enum to store the privs
Enum Privs
{
	$DeleteFile			= 0,
	$UploadFile			= 1,
	$DownloadFile			= 2,
	$RenameFile			= 3,
	$MoveFile			= 4,
	$CreateFolder			= 5,
	$DeleteFolder			= 6,
	$RenameFolder			= 7,
	$MoveFolder			= 8,
	$ReadChat			= 9,
	$SendChat			= 10,
	$CreateChat			= 11,
	$CloseChat			= 12
};
// A simple function to print what privs are enabled
Function PrintPrivs( $data )
{
	foreach( Enumerate('Privs') as my $Key => my $Value )
	{
		my $Status = Vec($data, $Value, 1);
		if($Status) // Only show privs we can use
			say "Priv '$Key' Access is '$Status'";
	}
}
// Define a variable to hold the bit vector
my $Access = null;
// Set privs in the bit vector
Vec($Access, Privs->$UploadFile, 1) = true;
Vec($Access, Privs->$CreateFolder, 1) = true;
Vec($Access, Privs->$ReadChat, 1) = true;
Vec($Access, Privs->$CloseChat, 1) = true;
// Print the privs from the bit vector
say "Print Privs";
PrintPrivs($Access);
// Print the binary of the bit vector
printr $access;
// PRINTS
// Priv 'uploadfile' Access is '1'
// Priv 'createfolder' Access is '1'
// Priv 'readchat' Access is '1'
// Priv 'closechat' Access is '1'
// Binary
// (
//     [0] => 34
//     [1] => 18
// )
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox