Added bool viper data type

master
bixb922 2024-05-03 19:34:15 -04:00
rodzic 4e0a487218
commit 03966b45c2
1 zmienionych plików z 59 dodań i 13 usunięć

@ -62,7 +62,7 @@ Advantages of the @micropython.native decorator: no change to the code is needed
Advantage of the @micropython.viper decorator: the result can be faster, especially if integer and array operations are involved. But it is necessary to change the code.
# The viper data types: int, uint, ptr32, ptr16 and ptr8
# The viper data types: int, uint, bool, ptr32, ptr16 and ptr8
These data types are very fast. They are not implemented as an MicroPython object but as a raw variable. They can be only used within a viper decorated function.
@ -94,6 +94,7 @@ In case you are familiar with C: The viper data types are similar to some C lang
|----------------|----------------------|------|
|`int` |`long int` | 32 bit signed integer|
|`uint` | `unsigned long int`| 32 bit unsigned integer |
|`bool` | `long int`| 32 bit signed integer, but only 0 (False) and not zero (True) is used |
|`ptr32` | `*long int` | memory pointer to a 32 bit signed integer |
|`ptr16` |`*unsigned short int` |memory pointer to a 16 bit unsigned integer |
|`ptr8` | `*unsigned char`|memory pointer to an 8 bit unsigned integer |
@ -103,8 +104,8 @@ In case you are familiar with C: The viper data types are similar to some C lang
* The viper data types only exist in a viper function
* The viper data types are detected at compile time (statically, before the program starts to run)
* They are not MicroPython objects but raw variables
* The associated functions `int()`, `uint()`, `ptr8()`, `ptr16()` and `ptr32()` are type casts (similar to C language)
* The MicroPython `int` object we all know is different from the viper `int` inside a viper function. If needed, the MicroPython `int` can still be accessed as `builtins.int` (`import builtins` first)
* The associated functions `int()`, `uint()`, `bool()` `ptr8()`, `ptr16()` and `ptr32()` are type casts (similar to C language)
* The MicroPython `int` object we all know is different from the viper `int` inside a viper function. If needed, the MicroPython `int` can still be accessed as `builtins.int` (`import builtins` first). Same with `bool`.
* Operations are very fast
## The viper int data type
@ -133,7 +134,7 @@ As it is usual in Python, a viper variable is of type viper `int when you assig
```
If the variable is created by assigning an expression, the viper code emitter will evaluate the expression at compile time.
Be aware: Integer expressions outside what is called the "small integer" range of MicroPython are not viper `int` but `builtins.int`. On most architectures a MicroPython small integer falls is -2\*\*29 and 2\*\*29-1.
Be aware: Integer expressions outside of what is called the "small integer" range of MicroPython are not viper `int` but `builtins.int`. On most architectures a MicroPython small integer falls is -2\*\*29 and 2\*\*29-1.
For example:
```py
@ -234,7 +235,7 @@ A viper ```int``` is not an object, and thus does not support methods such as ``
The \*\* operator (exponentiation, `__pow__`) is not implemented for viper ```int```.
In versions MicroPython 1.22 and prior, unary minus is not implemented, instead of `x=-a` use `x=0-a`. In version 1.23 the unary minus is being implemented, but not completely yet.
Be aware: In versions MicroPython 1.22 and prior, unary minus is not implemented, instead of `x=-a` use `x=0-a`. In version 1.23 the unary minus is being implemented, but not completely yet, so until further confirmation it's best to avoid unary minus, and use subtraction from zero instead.
Be aware: Do not use shift left or right with a negative value, i.e. `x<<(-1)` or `x>>(-1)` should not be used because the result is undefined. This mirrors the C language definition for shifting. Unlike regular MicroPython, there is no check (no exception raised) for negative shift amounts.
@ -279,6 +280,38 @@ def test_uint_int_assignments():
print(f"{y=} int(y)={y=:08x}, expected 0xffffffff")
```
## The viper bool data type
A bool viper variable can be True or False. Boolean expressions are evaluated using the viper bool data type. This makes logic computations fast.
You create a bool viper variable by assigning `True`, `False` or the result of a logical expression of constants and viper bool variables that yields `True` or `False`, for example:
```py
@micropython.viper
def function_with_bools():
a = True
y = 1
z = 2
b = y < z
c = bool(y)
# Now a, b and c are viper bool variables
# and a, b, and c are True
```
You can convert a `int` or `uint` to bool using the `bool()` cast function. A zero value is interpreted as False, any value different from zero is interpreted as True.
Similar to `builtins.int` for the viper `int` data type, `builtins.bool` can be used to have the MicroPython boolean data type available.
As a note of minor interest, the bool viper variable is stored as a 32 bit integer:
```py
@micropython.viper
def cast_bools():
x = int(12345)
b = bool(x)
y = int(b)
# Now y holds the same value as x
```
Similar to `int()` and `uint()`, `bool()` is a cast operator. If used on a viper variable, only the type is changed, no conversion takes place (similar to casting in C language).
## The viper ptr32, ptr16 and ptr8 data types
These data types are pointers to memory, similar to a C language `long *p;` or `unsigned char *p`. This is rather unusual for Python, where no pointers exist and memory access is well hidden within objects that protect that access.
@ -289,10 +322,11 @@ You can assign to x[n], modifying the memory contents. There is no bounds checki
### Declaration of pointer variables with type hints on function argument
```py
@micropython.viper
def myfunction( x:ptr32 )->int:
def myfunction( x:ptr32, b:bool )->int:
print(x[0], x[1], x[2] ) # will print 1, 2, 3, 4
return x[1]
myfunction( array.array("l", (1,2,3,4)))
```
## Declaration of pointer variables with ptr32(), ptr16() and ptr8()
@ -394,11 +428,18 @@ The call overhead for a viper function is substantially lower than call overhead
For integer parameters, use the `int` or `uint` type hint to get automatic conversion to a viper int. The conversion is done internally by MicroPython using the `int()` or `uint()` cast operator respectively:
```py
@micropython.viper
def my_function( x:int, b:uint ):
# now x and b are viper data type variables
def my_function( x:int, z:uint ):
# now x and z are viper data type variables
....
```
Similarly, a boolean parameter is cast automatically to a viper bool:
```py
@micropython.viper
def my_function( b:bool ):
# b is a viper bool variable
....
```
For arrays and bytearrays, use the ptr32, ptr16 and ptr8 type hints in the function parameters to get fast access to the arrays. The cast from an array to a pointer is done automatically while processing the call, i.e. a ptr8(), ptr16() or ptr32() cast is applied automatically to the argument.
```py
@ -453,7 +494,7 @@ def fun2( mypointer:ptr8 ):
A side effect of this behavior is that `type(viper_variable)` always returns class `builtins.int`, because the viper variable is converted to a `builtins.int` during the call process.
Talking about detecting type: inside a viper function, `isinstance(viper_variable,int)` will give a compile-time error `NotImplementedError: conversion to object`, since `int` is a viper data type, not a MicroPython class. However, `isinstance(viper_variable, builtins.int)` will return `True` since the `viper_variable` will be converted to a MicroPython `builtins.int` automatically during the call process.
Talking about detecting type: inside a viper function, `isinstance(viper_variable,int)` will give a compile-time error `NotImplementedError: conversion to object`, since `int` is a viper data type, not a MicroPython class. However, `isinstance(viper_variable, builtins.int)` will return `True` since the `viper_variable` will be converted to a MicroPython `builtins.int` automatically during the call process. This also applies to `bool`.
## Viper function return values
@ -461,10 +502,13 @@ If the function returns a viper variable, a return type hint must be supplied, f
```py
@micropython.viper
function returns_integer(param1:int)->int:
def function_returns_integer(param1:int)->int:
return 1
@micropython.viper
def function_returns_bool(x:int)->bool:
return True
```
The conversion of the return value back to `builtins.int` is done automatically.
The conversion of the return value back to `builtins.bool` is done automatically.
You can return a pointer in a viper function, but you must add the return type hint as ->ptr8, ->ptr16 or ->ptr32. The pointer returned is converted to a `builtins.int` and it's value will be the memory address of the array. The addresses are always byte addresses. The function that uses that returned integer must cast it to a pointer of the correct type to make things work, for example:
```py
@ -539,6 +583,7 @@ You can assign a viper integer to a global variable, it gets converted to a `bui
The global variable `x` is of type `builtins.int` and you cannot mix viper `int` with `builtins.int`. In the example, `10` is a viper `int` constant and has to be converted to a `builtins.int` before operating.
For viper bool variables, similar rules apply.
## Example of nonlocal and closure with viper functions
@ -607,10 +652,11 @@ This is a workaround: `x[builtins.int(0):builtins.int(2)]`
## async and generators
Viper decorated functions cannot have the async attribute (it crashes) nor be generators (`NotImplementedError: native yield` compile time error)
Viper decorated functions cannot have the async attribute (it crashes) nor be generators (`NotImplementedError: native yield` compile time error`)
Workaround: async functions and generators can call viper functions.
However, a viper function can call a generator.
## Type hints in the body of a viper function
@ -624,7 +670,7 @@ def myfunction():
step:int = 0
```
You can't use `builtins.int` as type hint, and there is no `type` statement in MicroPython. So `builtins.int` will be always without type hint.
You can't use `builtins.int` as type hint, and there is no `type` statement in MicroPython. So `builtins.int` will be always written without type hint.
## Test if a variable is of type viper int
In compile time: