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