librdesc
Loading...
Searching...
No Matches
stack.c
1// SPDX-FileCopyrightText: 2025-2026 Metehan Selvi <me@metehanselvi.com>
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4
5#include "../include/stack.h"
6#include "common.h"
7#include "test_instruments.h"
8
9#include <stdbool.h>
10#include <stdint.h>
11#include <stdlib.h>
12#include <stddef.h>
13#include <string.h>
14
15
16#ifndef STACK_INITIAL_CAP
17#define STACK_INITIAL_CAP 32
18#endif
19
20#ifndef STACK_MAX_CAP
21#define STACK_MAX_CAP SIZE_MAX
22#endif
23
24
37 size_t len ;
38 size_t cap ;
39 size_t element_size ;
40 char elements[] ;
41};
42
43
44static inline void *elem_at(struct rdesc_stack *s, size_t i)
45{
46 runtime_assertion(s->len >= i, "range overflow");
47
48 return cast(void *, &s->elements[i * s->element_size]);
49}
50
51/* return non-zero value if reallocation failure */
52static inline int resize_stack(struct rdesc_stack **s, size_t cap)
53{
54 struct rdesc_stack *new =
55 xrealloc(*s, sizeof(struct rdesc_stack) + cap * (*s)->element_size);
56
57 if (new != NULL) {
58 *s = new;
59 (*s)->cap = cap;
60
61 return 0;
62 } else {
63 return 1;
64 }
65}
66
67/* returns non-zero value if resize failure */
68static int stack_reserve(struct rdesc_stack **s, size_t reserved_space)
69{
70 size_t increased_cap = (*s)->cap;
71
72 while (increased_cap <= (*s)->len + reserved_space) {
73 if (increased_cap > STACK_MAX_CAP / (2 * (*s)->element_size))
74 return 1;
75
76 increased_cap *= 2;
77 }
78
79 if (increased_cap != (*s)->cap)
80 return resize_stack(s, increased_cap);
81
82 return 0;
83}
84
85void rdesc_stack_init(struct rdesc_stack **s, size_t element_size)
86{
87 *s = xmalloc(sizeof(struct rdesc_stack) + STACK_INITIAL_CAP * element_size);
88
89 if (*s == NULL)
90 return;
91
92 (*s)->element_size = element_size;
93 (*s)->len = 0;
94 (*s)->cap = STACK_INITIAL_CAP;
95}
96
97void rdesc_stack_destroy(struct rdesc_stack *s)
98{
99 free(s);
100}
101
102void rdesc_stack_reset(struct rdesc_stack **s)
103{
104 if ((*s)->cap > STACK_INITIAL_CAP) {
105 resize_stack(s, STACK_INITIAL_CAP);
106 }
107
108 (*s)->len = 0;
109}
110
111void *rdesc_stack_at(struct rdesc_stack *s, size_t i)
112{
113 return elem_at(s, i);
114}
115
116void *rdesc_stack_multipush(struct rdesc_stack **s, void *element, size_t count)
117{
118 /* return null if grow failed */
119 if (stack_reserve(s, count) || (xmultipush(count)))
120 return NULL;
121
122 void *top = elem_at(*s, (*s)->len);
123
124 if (element)
125 memcpy(top, element, (*s)->element_size * count);
126 (*s)->len += count;
127
128 return top;
129}
130
131void *rdesc_stack_push(struct rdesc_stack **s, void *element)
132{
133 return rdesc_stack_multipush(s, element, 1);
134}
135
136void *rdesc_stack_multipop(struct rdesc_stack **s, size_t count)
137{
138 runtime_assertion((*s)->len >= count, "stack underflow");
139
140 size_t decreased_cap = (*s)->cap;
141
142 while ((*s)->len * 4 <= decreased_cap &&
143 decreased_cap >= STACK_INITIAL_CAP * 2)
144 decreased_cap /= 2;
145
146 (*s)->len -= count;
147
148 if (decreased_cap != (*s)->cap)
149 resize_stack(s, decreased_cap);
150
151 return elem_at(*s, (*s)->len);
152}
153
154void *rdesc_stack_top(struct rdesc_stack *s)
155{
156 return elem_at(s, s->len - 1);
157}
158
159void *rdesc_stack_pop(struct rdesc_stack **s)
160{
161 return rdesc_stack_multipop(s, 1);
162}
163
164size_t rdesc_stack_len(const struct rdesc_stack *s)
165{
166 return s->len;
167}
Default implementation of the stack.
Definition stack.c:36
size_t len
Definition stack.c:37
size_t element_size
Definition stack.c:39
char elements[]
Definition stack.c:40
size_t cap
Definition stack.c:38