1 /*
2 * Copyright (c) 2007 - 2016 Joseph Gaeddert
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 //
24 // Windows, defined by macro
25 //
26
27 #include "liquid.internal.h"
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32
WINDOW(_s)33 struct WINDOW(_s) {
34 T * v; // allocated array pointer
35 unsigned int len; // length of window
36 unsigned int m; // floor(log2(len)) + 1
37 unsigned int n; // 2^m
38 unsigned int mask; // n-1
39 unsigned int num_allocated; // number of elements allocated
40 // in memory
41 unsigned int read_index;
42 };
43
44 // create window buffer object of length _n
WINDOW(_create)45 WINDOW() WINDOW(_create)(unsigned int _n)
46 {
47 // validate input
48 if (_n == 0) {
49 fprintf(stderr,"error: window%s_create(), window size must be greater than zero\n",
50 EXTENSION);
51 exit(1);
52 }
53
54 // create initial object
55 WINDOW() q = (WINDOW()) malloc(sizeof(struct WINDOW(_s)));
56
57 // set internal parameters
58 q->len = _n; // nominal window size
59 q->m = liquid_msb_index(_n); // effectively floor(log2(len))+1
60 q->n = 1<<(q->m); // 2^m
61 q->mask = q->n - 1; // bit mask
62
63 // number of elements to allocate to memory
64 q->num_allocated = q->n + q->len - 1;
65
66 // allocte memory
67 q->v = (T*) malloc((q->num_allocated)*sizeof(T));
68 q->read_index = 0;
69
70 // reset window
71 WINDOW(_reset)(q);
72
73 // return object
74 return q;
75 }
76
77 // recreate window buffer object with new length
78 // _q : old window object
79 // _n : new window length
WINDOW(_recreate)80 WINDOW() WINDOW(_recreate)(WINDOW() _q, unsigned int _n)
81 {
82 // TODO: only create new window if old is too small
83
84 if (_n == _q->len)
85 return _q;
86
87 // create new window
88 WINDOW() w = WINDOW(_create)(_n);
89
90 // copy old values
91 T* r;
92 WINDOW(_read)(_q, &r);
93 //memmove(q->v, ...);
94 unsigned int i;
95 if (_n > _q->len) {
96 // new buffer is larger; push zeros, then old values
97 for (i=0; i<(_n-_q->len); i++)
98 WINDOW(_push)(w, 0);
99 for (i=0; i<_q->len; i++)
100 WINDOW(_push)(w, r[i]);
101 } else {
102 // new buffer is shorter; push latest old values
103 for (i=(_q->len-_n); i<_q->len; i++)
104 WINDOW(_push)(w, r[i]);
105 }
106
107 // destroy old window
108 WINDOW(_destroy)(_q);
109
110 return w;
111 }
112
113 // destroy window object, freeing all internally memory
WINDOW(_destroy)114 void WINDOW(_destroy)(WINDOW() _q)
115 {
116 // free internal memory array
117 free(_q->v);
118
119 // free main object memory
120 free(_q);
121 }
122
123 // print window object to stdout
WINDOW(_print)124 void WINDOW(_print)(WINDOW() _q)
125 {
126 printf("window [%u elements] :\n", _q->len);
127 unsigned int i;
128 T * r;
129 WINDOW(_read)(_q, &r);
130 for (i=0; i<_q->len; i++) {
131 printf("%4u", i);
132 BUFFER_PRINT_VALUE(r[i]);
133 printf("\n");
134 }
135 }
136
137 // print window object to stdout (with extra information)
WINDOW(_debug_print)138 void WINDOW(_debug_print)(WINDOW() _q)
139 {
140 printf("window [%u elements] :\n", _q->len);
141 unsigned int i;
142 for (i=0; i<_q->len; i++) {
143 // print read index pointer
144 if (i==_q->read_index)
145 printf("<r>");
146
147 // print window value
148 BUFFER_PRINT_LINE(_q,i)
149 printf("\n");
150 }
151 printf("----------------------------------\n");
152
153 // print excess window memory
154 for (i=_q->len; i<_q->num_allocated; i++) {
155 BUFFER_PRINT_LINE(_q,i)
156 printf("\n");
157 }
158 }
159
160 // reset window object (initialize to zeros)
WINDOW(_reset)161 void WINDOW(_reset)(WINDOW() _q)
162 {
163 // reset read index
164 _q->read_index = 0;
165
166 // clear all allocated memory
167 memset(_q->v, 0, (_q->num_allocated)*sizeof(T));
168 }
169
170 // read window buffer contents
171 // _q : window object
172 // _v : output pointer (set to internal array)
WINDOW(_read)173 void WINDOW(_read)(WINDOW() _q, T ** _v)
174 {
175 // return pointer to buffer
176 *_v = _q->v + _q->read_index;
177 }
178
179 // index single element in buffer at a particular index
180 // _q : window object
181 // _i : index of element to read
182 // _v : output value pointer
WINDOW(_index)183 void WINDOW(_index)(WINDOW() _q,
184 unsigned int _i,
185 T * _v)
186 {
187 // validate input
188 if (_i >= _q->len) {
189 fprintf(stderr,"error: window_index(), index value out of range\n");
190 exit(1);
191 }
192
193 // return value at index
194 *_v = _q->v[_q->read_index + _i];
195 }
196
197 // push single element onto window buffer
198 // _q : window object
199 // _v : single input element
WINDOW(_push)200 void WINDOW(_push)(WINDOW() _q, T _v)
201 {
202 // increment index
203 _q->read_index++;
204
205 // wrap around pointer
206 _q->read_index &= _q->mask;
207
208 // if pointer wraps around, copy excess memory
209 if (_q->read_index == 0)
210 memmove(_q->v, _q->v + _q->n, (_q->len-1)*sizeof(T));
211
212 // append value to end of buffer
213 _q->v[_q->read_index + _q->len - 1] = _v;
214 }
215
216 // write array of elements onto window buffer
217 // _q : window object
218 // _v : input array of values to write
219 // _n : number of input values to write
WINDOW(_write)220 void WINDOW(_write)(WINDOW() _q,
221 T * _v,
222 unsigned int _n)
223 {
224 // TODO make this more efficient
225 unsigned int i;
226 for (i=0; i<_n; i++)
227 WINDOW(_push)(_q, _v[i]);
228 }
229
230