Skip to content

Commit bfcac26

Browse files
Merge pull request #23 from ZeroIntensity/new-version
2.0.0
2 parents 5b711c7 + 68dbf00 commit bfcac26

39 files changed

+2181
-2686
lines changed

README.md

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,27 @@
77
Why would you ever need this
88

99
- [Documentation](https://pointerspy.netlify.app/)
10-
- [Repository](https://github.com/ZeroIntensity/pointers.py)
10+
- [Source](https://github.com/ZeroIntensity/pointers.py)
1111
- [PyPI](https://pypi.org/project/pointers.py)
1212

1313
### Examples
1414

15-
```py
16-
from pointers import Pointer, decay
17-
18-
a: str = '123'
19-
b: str = 'abc'
20-
21-
@decay
22-
def move(ptr_a: Pointer[str], ptr_b: Pointer[str]):
23-
ptr_a <<= ptr_b
24-
25-
move(a, b)
26-
print(a, b) # abc abc
27-
```
28-
2915
```py
3016
from pointers import _
3117

32-
ptr = _&"hello world" # creates a new pointer object
33-
assert _*ptr == "hello world"
18+
text: str = "hello world"
19+
ptr = _&text # creates a new pointer object
20+
ptr <<= "world hello"
21+
print(text) # world hello
3422
```
3523

3624
```py
37-
from pointers import fopen, fprintf, fclose
25+
from pointers import c_malloc as malloc, c_free as free, strcpy, printf
3826

39-
file = fopen("/dev/null", "w") # assigns file to the c FILE* type
40-
fprintf(file, "hello world")
41-
fclose(file)
27+
ptr = malloc(3)
28+
strcpy(ptr, "hi")
29+
printf("%s\n", ptr)
30+
free(ptr)
4231
```
4332

4433
### Features

docs/allocation.md

Lines changed: 100 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,100 @@
1-
# Allocation
2-
3-
## Malloc
4-
5-
If you are familiar with C, then you should be familiar with the `malloc` function.
6-
7-
You can use this in pointers.py, like so:
8-
9-
```py
10-
from pointers import malloc, MallocPointer
11-
12-
ptr: MallocPointer[str] = malloc(52) # we have to specify type manually
13-
```
14-
15-
**Note:** If the memory allocation fails, a `pointers.AllocationError` is raised.
16-
17-
Instead of returning a `Pointer` object, `malloc` returns a `pointers.MallocPointer` object.
18-
19-
To assign data to the pointer, we have to use data movement:
20-
21-
```py
22-
from pointers import malloc, MallocPointer
23-
24-
ptr: MallocPointer[str] = malloc(52)
25-
ptr <<= "abc"
26-
print(~ptr)
27-
```
28-
29-
The size that we pass to `malloc` must match the data we move to the memory. In the example above, the string `"abc"` has a size of 52 bytes.
30-
31-
If you give an invalid size, then an `InvalidSizeError` is raised.
32-
33-
### Identity checking
34-
35-
Pointers.py has an known issue with identity checking when using `malloc` or `calloc`
36-
37-
Lets take the following code as an example:
38-
39-
```py
40-
from pointers import malloc, free
41-
42-
mem = malloc(28)
43-
mem <<= 1
44-
45-
assert ~mem is 1 # raises an AssertionError
46-
free(mem)
47-
```
48-
49-
**What's happening here?** Lets print out the memory addresses of `~mem` and `1`:
50-
51-
```py
52-
mem = malloc(28)
53-
mem <<= 1
54-
55-
print(id(~mem), id(1))
56-
```
57-
58-
In my case, this returns `26493552 9788992`, even though the address for `1` should always be the same.
59-
60-
This means that the `is` operator will not work when dereferencing.
61-
62-
## Malloc Pointer
63-
64-
`MallocPointer` is extremely similar to `Pointer`, with a few differences:
65-
66-
- `freed` and `assigned` property are present.
67-
- Attempting to read property `type` results in a `IsMallocPointerError`
68-
- Pointer assignment unsupported (also results in a `IsMallocPointerError`)
69-
70-
## Free
71-
72-
To free the allocated memory from `malloc`, we must use `free`.
73-
74-
`free` is very simple. Just pass the `MallocPointer` object, and it will do the rest.
75-
76-
```py
77-
from pointers import malloc, free
78-
79-
ptr = malloc(52)
80-
ptr <<= "abc"
81-
free(ptr) # frees the memory
82-
```
83-
84-
A `MemoryError` is raised if you try to access the memory after it is freed.
85-
86-
## Realloc
87-
88-
If you need to change the size of the allocated memory, you can use `realloc`. Lets use the following code as an example:
89-
90-
```py
91-
from pointers import malloc, free, realloc
92-
93-
ptr = malloc(52)
94-
ptr <<= "abc"
95-
realloc(ptr, 53) # allocates one more byte
96-
ptr <<= "abcd" # works correctly
97-
free(ptr)
98-
```
99-
100-
**Note:** Like `malloc`, if the resize fails, `pointers.AllocationError` is raised.
101-
102-
Unlike in C, `realloc` in pointers.py **does not** return a pointer to the new memory. Instead, it simply allocates it and lets you use the old one.
103-
104-
## Calloc
105-
106-
`calloc` is a bit more complicated than `malloc` and `realloc`. Instead of allocating one block of memory, it allocates multiple blocks of a specified size.
107-
108-
Basic usage:
109-
110-
```py
111-
from pointers import calloc
112-
113-
memory = calloc(3, 28)
114-
memory <<= 5
115-
116-
print(~memory)
117-
```
118-
119-
`calloc` also **does not** return a `MallocPointer` object. Instead, it returns its own `CallocPointer` object.
120-
121-
Now, to use the other allocated chunks, we can use pointer arithmetic.
122-
123-
```py
124-
memory = calloc(4, 28)
125-
memory <<= 1 # assigns first chunk to 1
126-
memory += 1 # access next chunk
127-
memory <<= 2 # assigns this chunk to 2
128-
print(~memory)
129-
```
130-
131-
If you attempt to skip more chunks than are allocated, a `NotEnoughChunks` error is raised:
132-
133-
```py
134-
memory = calloc(1, 28)
135-
memory += 2 # NotEnoughChunks: chunk index is 2, while allocation is 1
136-
```
137-
138-
### Safe Mode
139-
140-
In older versions of pointers.py, the way `calloc` worked internally was broken. In these versions, the `calloc_safe` function needed to be used to get it working properly.
141-
142-
```py
143-
from pointers import calloc_safe
144-
145-
mem = calloc_safe(4, 28)
146-
147-
for index, ptr in enumerate(mem):
148-
ptr <<= index + 1
149-
150-
print(' '.join([~i for i in mem])) # without calloc_safe, this used to cause a segfault
151-
```
152-
153-
`calloc_safe` **did not** use pointers and was holding a dictionary containing values to prevent segfaults.
154-
155-
Since 1.2.4, this issue has been patched. For more information on what happened with the broken implementation, see the [GitHub issue](https://github.com/ZeroIntensity/pointers.py/issues/11).
156-
157-
### Calloc Pointer
158-
159-
`CallocPointer` inherits from `MallocPointer`, so it's mostly the same, but has a few different features:
160-
161-
- `safe`, `chunks`, `chunk_size`, and `current_index` properties are present.
162-
- Dereferencing using `*` is not supported
1+
# Allocation
2+
3+
## Basics
4+
5+
We can use memory functions (`malloc`, `free`, `calloc`, `realloc`) the same way you would use them in C, and use them via the pointer API.
6+
7+
Here's an example:
8+
9+
```py
10+
from pointers import malloc, free
11+
12+
ptr = malloc(28) # 28 is the size of integers larger than 0
13+
free(ptr)
14+
```
15+
16+
We can dereference the same way we did earlier, but first, we need to actually put something in the memory. We can do this via data movement:
17+
18+
```py
19+
from pointers import malloc, free
20+
21+
ptr = malloc(28)
22+
ptr <<= 1
23+
print(*ptr)
24+
free(ptr)
25+
```
26+
27+
Data movement is much safer when using memory allocation, since we aren't actually overwriting memory tracked by Python.
28+
29+
We also aren't overwriting any existing objects, we are just putting the object into a memory space.
30+
31+
Here's a quick example:
32+
33+
```py
34+
from pointers import malloc, free
35+
36+
ptr = malloc(28)
37+
ptr <<= 1
38+
print(*ptr)
39+
ptr <<= 2
40+
print(*ptr, 1) # prints out "2 1", since we dont have to overwrite the 1 object itself!
41+
free(ptr)
42+
```
43+
44+
We can bypass size limits the same way as before, but again, this is extremely discouraged. Instead, we should use `realloc`.
45+
46+
## Reallocation
47+
48+
The `realloc` function works a bit differently in pointers.py. We don't reassign the pointer like you would in C:
49+
50+
```py
51+
ptr = realloc(ptr, 28)
52+
```
53+
54+
Instead, we can just call `realloc` on the object directly, like so:
55+
56+
```py
57+
from pointers import malloc, realloc, free
58+
59+
ptr = malloc(24)
60+
ptr <<= 0
61+
realloc(ptr, 28)
62+
free(ptr)
63+
```
64+
65+
## Identity
66+
67+
Identity of objects in CPython are defined by their memory address, so using `is` on objects inside allocated memory won't work properly:
68+
69+
```py
70+
from pointers import malloc, free
71+
import sys
72+
73+
text: str = "hello world"
74+
ptr = malloc(sys.getsizeof(text))
75+
ptr <<= text
76+
print(~ptr is text) # False
77+
```
78+
79+
## Arrays
80+
81+
We can allocate an array using `calloc`:
82+
83+
```py
84+
from pointers import calloc, free
85+
86+
ptr = calloc(4, 28) # allocate an array of 4 slots of size 28
87+
```
88+
89+
You can (somewhat) use an allocated array as you would in C:
90+
91+
```py
92+
from pointers import calloc, free
93+
94+
array = calloc(4, 28)
95+
96+
for index, ptr in enumerate(array):
97+
ptr <<= index
98+
99+
print(ptr[1]) # prints out "1"
100+
```

0 commit comments

Comments
 (0)