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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
|
type error = enum int8 (
### Generic error code when no more specific one exists
generic = -1
### Out of memory
outofmem = -2
### Internal error, caused by a bug (or by memory corruption)
internal = -3
### Not supported. The operation is optional, and is not available
notsupp = -4
### A parameter is invalid
param = -5
### Out of range
outofrange = -6
### Non-existent
nonexistent = -7
)
func <T>alloc(size bytes = sizeof T, size align = alignof T) return uninit rwref takeown T|error.outofmem
# FIXME how should this work with ownership inside the returned data (for example if it is a struct)
func <T>calloc(size bytes = sizeof T, size align = alignof T) return rwref takeown T|error.outofmem
func <T>free(ref takeown T elem, size = sizeof T)
func <T>free_opt(?ref takeown T elem, size = sizeof T)
type Arena = private
func arena_new(shared ?rwref Arena base_arena) return takeown Arena|error.outofmem
func arena_free_all(rwref takeown Arena this)
func <T>arena_alloc(shared rwref Arena this, size bytes = sizeof T, size align = alignof T) return uninit rwref own(this) T|error.outofmem
func <[len]T>alloc_array(size elembytes = T, size len) return uninit rwref takeown T|error.outofmem
# FIXME how should this work with ownership inside the array
func <[len]T>calloc_array(size elembytes = T, size len) return uninit rwref takeown T|error.outofmem
# FIXME uninit from new location!
func <[len]T>realloc_array(size elembytes = T, size len, ref takeown [len]T array) return uninit rwref takeown T|error.outofmem
func <[len]T>crealloc_array(size elembytes = T, size len, ref takeown [len]T array) return uninit rwref takeown T|error.outofmem
# it would also be nice to have a "realloc_if_no_move", "realloc_up_to"
func <[len]T>free_array(ref takeown [len]T array, size elembytes = T, size len)
# flexible alloc. does not require knowing the size when freeing, and allows reallocing (like C malloc)
func <T>flex_alloc(size bytes = sizeof T) return uninit rwref takeown T|error.outofmem
# TODO
openinterface <T>Eq
{
func equals(dedup ref T a, dedup ref T b) return bool
}
openinterface <T>Hashable
{
func hashcode(dedup ref this) return size
}
type CmpResult = enum (ALess = -1, Equal, AGreater)
openinterface <T>Cmp
{
func compare(dedup ref a, dedup ref b) return CmpResult
}
###
# Classes implementing this interface allow getting an iterator,
# which allows iterating (steppin through) elements in the object.
#
# @param T Element type
#
openinterface <T>Iterable
{
# TODO: Ownership of the iterator?
# - one iterator per list? but that uses memory for unused iterators
# - use only a single pointer? limits what objects we can iterate over
# - allocate a new object on the heap? would be nice to avoid.
# - declare a fixed size? i.e. all iterators are 4*size/pointer.
# - optionally heap allocate and require free'ing iterators?
###
# Returns an iterator of the object, that iterators through all
# elements. The object may not be modified while using the
# iterator.
#
# @return Iterator
#
func iter(ref this) return reading(this) <T>Iter
}
###
# An iterator, that allows iterating (stepping through) elements.
#
# @param T Element type
#
openinterface <T>Iter
{
###
# Whetver the iterator has more elements
func more(ref this) return bool
###
# Gets the current element, and moves the iterator forward
#
# Calling this method when more() returns false (or without calling it
# first), is forbidden.
func next(rwref this) return dedup ref T
}
###
# A set of elements without duplicates
#
# @param T Element type
#
classtree <T>Set implements <T>Iterable
{
CustomSet
HashSet [T implements Hash,Eq]
OrderedHashSet <T implements Hash,Eq>
TreeSet where T implements Cmp
size elemsize = sizeof T
###
# Adds a new element
#
# @return true if the element was added, false if it already existed
func add(rwref this, dedup ref takeown T elem) return bool|error.outofmem
###
# Checks if an element already exists in the set
func contains(ref this, dedup ref T elem) return bool
###
# Removes an element
#
# @return true if the element was removed. false if it didn't exist
func remove(rwref this, dedup ref dropown T elem) return bool
###
# Checks if the set is empty
func empty(ref this) return bool
###
# Returns the number of elements in the set
func count(ref this) return size
###
# Removes all elements from the set
func clear(wref this) when is_dedup T
}
###
# A list of elements
#
# @param T Element type
#
classtree <T>List implements <T>Iterable
{
CustomSet
###
# An array list. Uses little memory and allows very fast iteration.
ArrayList
###
# A chunked list. Uses little memory and allows very fast iteration.
ChunkedList
###
# A linked list. Allows fast insertions and removal in the middle
# of the list
LinkedList
size elemsize = sizeof T
###
# Adds a new element at the end of the list
#
# @param elem Element to add
# @return Nothing, unless there is an out-of-memory error
func append(rwref this, dedup ref takeown T elem) return |error.outofmem
###
# Adds a new element at the beginning of the list
#
# @param elem Element to add
# @return Nothing, unless there is an out-of-memory error
func prepend(rwref this, dedup ref takeown T elem) return |error.outofmem
###
# Inserts a new element at the given position. After the insertion,
# any element at that position and any later elements will appear
# at one step higher.
#
# @param elem Element to add
# @return Nothing, unless there is an out-of-memory error
func insert(rwref this, dedup ref takeown T elem, size index) return |error.outofmem
###
# Removes the first element
#
# @return The element that was removed, if any existed.
func pop(rwref this) return dedup ref takeown T|error.nonexistent
###
# Removes an element
#
# @return The element that was removed, if it existed.
func remove(rwref this, size index) return dedup ref takeown T|error.nonexistent
###
# Checks if the set is empty
func empty(ref this) return bool
###
# Returns the number of elements in the set
func count(ref this) return size
###
# Removes all elements
func clear(wref this) when is_dedup T
}
###
# Bitmask for matching various strings:
# - whitespace/letters/digits
# - hexadecimal digits
# - identifiers
# - html/sgml/xml
# - base64
typedef CharGroup = bitmask ushort (
Control
Space
Digit
HexLower # 4
HexUpper
OtherLower
OtherUpper
Plus # 8
Minus
Underscore
Equals
Less # 12
Greater
Slash
DblQuote
SingleQuote # 16
)
# We should also have an interface for raw bytes (e.g. like memmem, memchr, memrchr)
openinterface CharSeq extends <uint32>Iterable, Eq<CharSeq>, Cmp<CharSeq>, Hsh<CharSeq>
{
func begins_with(ref this, ref CharSeq seq) return true
func begins_with_asciicase(ref this, ref CharSeq seq) return true
# FIXME cannot return errors with "size" type... or can we require size to be non-negative?
#func hash_beginning(ref this, size length) return size|error.outofrange
func hash_beginning(ref this, size length) return size
func hash_to_char(ref this, uint32 char) return size
func hash_to_chargroup(ref this, CharGroup chargroup) return size
# TODO. would be nice to have
# - strspn
# - strcspn
# - strchr
# - strstr
# And maybe (slow on zero-terminated strings)
# - strrchr
# - strrstr
# - ends_with
# And maybe (needs sub-sequence handling)
# - substr
# - trim
# - pointer-strspn i.e. strpbrk
# - pointer-strcspn
# - after_char
# - before_char
# - after_string
# - before_string
# - split (returning an iterator)
# - begins_with that returns a pointer
}
|