Repository navigation
Expand file tree
/
Copy pathstack.c
More file actions
188 lines (172 loc) · 5.56 KB
/
Copy pathstack.c
File metadata and controls
188 lines (172 loc) · 5.56 KB
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
#include "stack.h"
#include <sys/mman.h>
/* Initializes a stack with an initial capacity of 1.
* Returns NULL and prints an error if any allocation fails. */
stack* stack_init(void){
stack *s = malloc(sizeof(stack));
if (s == NULL){
perror("malloc");
return NULL;
}
s->top = 0;
s->capacity = 1;
s->stack = malloc((size_t)s->capacity*sizeof(stack_item));
if (s->stack == NULL){
perror("malloc");
free(s);
return NULL;
}
return s;
}
/* Resizes the stack: doubles capacity when full, halves it when less than
* half is used. Returns 0 on success, -1 on allocation failure. */
int stack_resize(stack *s){
int32_t new_capacity;
if (s->top == s->capacity)
new_capacity = s->capacity * 2;
else if (s->top < s->capacity / 4)
new_capacity = s->capacity / 2;
else
return 0;
stack_item *new_data = malloc((size_t)new_capacity * sizeof(stack_item));
if (new_data == NULL){
perror("malloc");
return -1;
}
memcpy(new_data, s->stack, (size_t)s->top * sizeof(stack_item));
free(s->stack);
s->stack = new_data;
s->capacity = new_capacity;
return 0;
}
/* Allocates and initializes a new array_instance with ref_count 1.
* Returns NULL on allocation failure. */
array_instance *new_instance(float *data, shape_t shape) {
array_instance *instance = malloc(sizeof(array_instance));
if (instance == NULL) {
perror("malloc");
return NULL;
}
instance->data = data;
instance->shape = shape;
instance->ref_count = 1;
instance->on_disk = 0;
instance->data_offset = 0;
return instance;
}
/* Pushes a new tensor onto the stack. Resizes if at capacity.
* Returns 0 on success, -1 on allocation failure. */
int stack_push(stack *s, float *arr, shape_t forma) {
array_instance *instance = new_instance(arr, forma);
if (instance == NULL)
return -1;
if (s->capacity == s->top){
if (stack_resize(s) != 0) { free(instance); return -1; }
}
stack_item item;
item.type = ITEM_TENSOR;
item.tensor = instance;
s->stack[s->top++] = item;
return 0;
}
/* Pushes an existing array_instance onto the stack, incrementing its ref_count.
* Returns 0 on success, -1 on allocation failure. */
int stack_push_instance(stack *s, array_instance *inst) {
if (s->capacity == s->top)
if (stack_resize(s) != 0) return -1;
inst->ref_count++;
stack_item item;
item.type = ITEM_TENSOR;
item.tensor = inst;
s->stack[s->top++] = item;
return 0;
}
/* Pops and returns the top element of the stack.
* Shrinks the stack if less than a quarter of capacity is used.
* Caller is responsible for calling instance_free when done. */
array_instance *stack_pop(stack *s){
if (s->top == 0){
fprintf(stderr, "stack underflow\n");
return NULL;
}
stack_item item = s->stack[--s->top];
if (item.type == ITEM_STRING) {
fprintf(stderr, "error: expected tensor, found string \"%s\"\n", item.filename);
free(item.filename);
if (s->top < s->capacity / 4) stack_resize(s);
return NULL;
}
if (s->top < s->capacity / 4)
stack_resize(s);
return item.tensor;
}
/* Returns a pointer to the top tensor without removing it or changing ref_count.
* Returns NULL on underflow or if the top item is not a tensor. */
array_instance *stack_peek(stack *s) {
if (s->top == 0) { fprintf(stderr, "stack underflow\n"); return NULL; }
stack_item *top = &s->stack[s->top - 1];
if (top->type != ITEM_TENSOR) {
fprintf(stderr, "error: expected tensor, found string\n");
return NULL;
}
return top->tensor;
}
/* Decrements ref_count and frees the instance if no references remain. */
void instance_free (array_instance *i){
if (i == NULL) return;
i->ref_count--;
if (i->ref_count <= 0){
if (i->on_disk) {
size_t mmap_size = (size_t)i->data_offset + (size_t)(i->shape.row * i->shape.col) * sizeof(float);
munmap((char *)i->data - i->data_offset, mmap_size);
} else {
free(i->data);
}
free(i);
}
}
/* Frees all instances on the stack, then frees the stack itself.
* Respects ref_count: instances shared via dup/over are freed only when all references are gone. */
void stack_free(stack *s){
while (s->top > 0)
stack_free_item(stack_pop_item(s));
free(s->stack);
free(s);
}
/* Pushes a filename string onto the stack. Makes a copy of the string.
* Returns 0 on success, -1 on allocation failure. */
int stack_push_string(stack *s, const char *filename){
if (s->capacity == s->top)
if(stack_resize(s) != 0) return -1;
stack_item item;
item.type = ITEM_STRING;
item.filename = malloc(strlen(filename) + 1);
if (item.filename == NULL) { perror("malloc"); return -1; }
strcpy(item.filename, filename);
s->stack[s->top++] = item;
return 0;
}
void stack_free_item(stack_item item) {
if (item.type == ITEM_TENSOR)
instance_free(item.tensor);
else if (item.type == ITEM_STRING)
free(item.filename);
}
int stack_push_item(stack *s, stack_item item) {
if (item.type == ITEM_TENSOR)
return stack_push_instance(s, item.tensor);
else
return stack_push_string(s, item.filename);
}
/* Pops and returns the top stack_item (tensor or string).
* Caller must free item.filename if type == ITEM_STRING. */
stack_item stack_pop_item(stack *s) {
stack_item empty = {0};
if (s->top == 0) {
fprintf(stderr, "stack underflow\n"); return empty;
}
stack_item item = s->stack[--s->top];
if (s->top < s->capacity / 4)
stack_resize(s);
return item;
}