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
|
#include <stdlib.h>
#include <string.h>
#include "circular.h"
circular* circular_new(size_t len);
void circular_delete(circular* c);
#if __GNUC__ > 4 && __GNUC__ <= 14
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
[[deprecated("implementation")]]
circular* circular_init(circular* c, size_t cap) {
if (c) {
if (cap) {
*c = (circular){
.cap = cap,
.tab = malloc(sizeof(double[cap])),
};
// Allocation failed.
if (!c->tab) c->cap = 0;
} else {
*c = (circular){ };
}
}
return c;
}
[[deprecated("implementation")]]
void circular_destroy(circular* c) {
if (c) {
free(c->tab);
circular_init(c, 0);
}
}
[[deprecated("implementation")]]
size_t circular_getlength(circular const* c) {
return c ? c->len : 0;
}
[[deprecated("implementation")]]
static size_t circular_getpos(circular const c[static 1], size_t pos) {
if (c->cap) {
pos += c->start;
pos %= c->cap;
}
return pos;
}
[[deprecated("implementation")]]
circular* circular_append(circular* c, double value) {
if (c) {
double* where = circular_element(c, c->len);
if (where) {
*where = value;
++c->len;
return c;
}
}
return nullptr;
}
[[deprecated("implementation")]]
double* circular_element(circular const* c, size_t pos) {
double* ret = nullptr;
if (c) {
if (pos < c->cap) {
pos = circular_getpos(c, pos);
ret = &c->tab[pos];
}
}
return ret;
}
[[deprecated("implementation")]]
double circular_pop(circular* c) {
double ret = 0.0;
if (c && c->len) {
double* p = circular_element(c, 0);
if (p) ret = *p;
++c->start;
--c->len;
}
return ret;
}
[[nodiscard("returned pointer replaces function argument")]]
[[deprecated("implementation")]]
circular* circular_resize(circular* c, size_t nlen) {
if (c) {
size_t len = c->len;
if (len > nlen) return nullptr;
size_t olen = c->cap;
if (nlen != olen) {
size_t ostart = circular_getpos(c, 0);
size_t nstart = ostart;
double* otab = c->tab;
double* ntab;
if (nlen > olen) {
ntab = realloc(c->tab, sizeof(double[nlen]));
if (!ntab) return nullptr;
// non-empty, and there were already two separate chunks
if (ostart+len > olen) {
size_t ulen = olen - ostart;
size_t llen = len - ulen;
if (llen <= (nlen - olen)) {
/* Copy the lower one up after the old end. */ /*@\label{cpy-lowchunk}*/
memcpy(ntab + olen, ntab,
llen*sizeof(double));
} else {
/* Move the upper one up to the new end. */ /*@\label{cpy-hichunk}*/
nstart = nlen - ulen;
memmove(ntab + nstart, ntab + ostart,
ulen*sizeof(double));
}
}
} else {
if (ostart+len > olen) {
// Two separate chunks; mv the upper one down to the new end.
size_t ulen = olen - ostart;
nstart = nlen - ulen;
memmove(otab + nstart, otab + ostart, ulen*sizeof(double));
} else {
// A single chunk
if (ostart + len > nlen) {
// Reallocation cuts the existing chunk in two.
memmove(otab, otab + ostart, len*sizeof(double));
nstart = 0;
}
}
if (nlen) {
// Now all data is saved in the conserved part of the array.
ntab = realloc(c->tab, sizeof(double[nlen]));
// If realloc fails in this case (would be weird), just overrule it.
if (!ntab) ntab = otab;
} else {
// There had been no elements and we were asked to reduce
// the buffer to 0 elements.
free(c->tab);
ntab = nullptr;
nstart = 0;
}
}
*c = (circular){
.cap = nlen,
.start = nstart,
.len = len,
.tab = ntab,
};
}
}
return c;
}
[[deprecated("implementation")]]
void circular_fput(circular* c, FILE* s) {
if (c) {
size_t len = circular_getlength(c);
double* tab = c->tab;
if (tab) {
fprintf(s, "%p+%zu (%zu+%zu):", (void*)tab, c->cap, c->start, len);
for (size_t i = 0; i < len; ++i) {
double* elp = circular_element(c, i);
// We know that c is not null, and so elp never will be.
if (!elp) unreachable();
fprintf(s, "\t%g", *elp);
}
fputc('\n', s);
return;
}
}
fputs("invalid circular\n", s);
}
|