summaryrefslogtreecommitdiff
path: root/doc/api/libstd/alloc.txt
blob: c2692a427dd0db94750e32fbbf1514a618da411c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
{
        title:  Allocation
        description:  libstd: Allocation
}

Memory Allocation
-----------------

    pkg std =
            generic mk	: (val : @a -> @a#)
            generic alloc	: (		-> @a#)
            generic zalloc	: (		-> @a#)
            generic free	: (v:@a#	-> void)
            generic slalloc	: (len : size	-> @a[:])
            generic slzalloc	: (len : size	-> @a[:])
            generic slgrow	: (sl : @a[:]#, len : size	-> @a[:])
            generic slzgrow	: (sl : @a[:]#, len : size	-> @a[:])
            generic slfree	: (sl : @a[:]	-> void)
            const bytealloc	: (sz:size	-> byte#)
            const zbytealloc	: (sz:size	-> byte#)
            const bytefree	: (m:byte#, sz:size	-> void)
    ;;

    generic mk	: (val : @a -> @a#)

`mk` creates a shallow copy of variable passed to it on the heap, returning a
pointer to the value that it allocated. It is conventionally used for creating
new copies of larger complex data structures, although it can be used to
heapify any value.

Returns: Pointer to fully initialized value of type '@a', based on the value
passed in.

    generic alloc	: (		-> @a#)
    generic zalloc	: (		-> @a#)

`alloc` allocates or free a single element of type @a, respectively. `zalloc`
does the same, but zeros the memory allocated before returning it. `free` is
used to return the memory allocated by these functions to the system. In
general, `mk` is preferred over these functions, as it does not leave any
values uninitialized.,

    generic slalloc	: (len : size	-> @a[:])
    generic slzalloc	: (len : size	-> @a[:])

`slalloc` allocates or frees a slice of `len` items of type @a. `slzalloc`
does the same, but zeros the memory allocated before returning it. `slfree`
is used to return the memory to the system.

    generic slgrow	: (sl : @a[:]#, len : size	-> @a[:])
    generic slzgrow	: (sl : @a[:]#, len : size	-> @a[:])

`slgrow` resizes the slize `sl` to length `len`, allocating the appropriate
amount of memory. `slzgrow` does the same, but any elements between the old
and new length are zeroed, as in slzalloc.

    generic free	: (v:@a#	-> void)
    generic slfree	: (sl : @a[:]	-> void)

`free` and `slfree` free the storage allocated allocated for the value or
slice passed to them , allowing it to be reused again later in the program.
This memory may be unmapped and returned to the operating system, or it may be
cached within the program.

Any uses of memory after a `free` call is invalid.

    const bytealloc	: (sz:size	-> byte#)
    const zbytealloc	: (sz:size	-> byte#)
    const bytefree	: (m:byte#, sz:size	-> void)

`bytealloc` `bytezalloc`, and `bytefree` are the low level raw-byte allocation
interface, returning blobs of bytes. Since the only way to use more than one
of these bytes is to cast to a different type, the generic versions are
generally a better choice.

Examples
---------

Overall, the examples here should not be unfamiliar to anyone who has used
either C or C++.

### Mk

`std.mk` should be used to create new, fully constructed values wherever
possible. The code for this looks like:

```{runmyr mk-example}
use std

type mytype =
	a : int
	b : char
	c : byte[:[
;;

const main = {
        var v

        v = std.mk([
            .a = 123
            .b = 'x'
            .c = "my string" /* this isn't heapified */
        ])

        std.free(v)
}
```

### Alloc and Zalloc

`alloc` and `zalloc` know the type that they're being assigned to, and use
this to calulate the size to allocate:


```{runmyr mk-example}
use std

const main = {
        var x : int#
        var y : int#

        x = std.alloc()
        y = std.zalloc()
        std.free(x)
        std.free(y)
}
```

### Slalloc and Slzalloc

`slalloc` and `slzalloc` take a size to allocate, but infer the type similar
to `alloc` and `zalloc`. They're freed with std.slfree() and slzfree().
Thankfully, unlike C++ delete and delete[], it's impossible to pass a slice
to the wrong free function.


```{runmyr mk-example}
use std

const main = {
        var x : int[:]

        x = std.slalloc(10)     /* slice of 10 ints */
        std.slfree(x)
}
```

Growing slices can be done using slgrow() and slzgrow():

```{runmyr mk-example}
use std

const main = {
        var x : int[:]

        x = std.slalloc(10)     /* slice of 10 ints */
        x = std.slzgrow(x, 20)     /* x[10:20] are guaranteed to be zeroed.*/
        std.slfree(x)
}
```