]> code.delx.au - pulseaudio/blob - src/pulsecore/mcalign.c
big s/polyp/pulse/g
[pulseaudio] / src / pulsecore / mcalign.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <string.h>
30
31 #include <pulse/xmalloc.h>
32
33 #include "mcalign.h"
34
35 struct pa_mcalign {
36 size_t base;
37 pa_memchunk leftover, current;
38 pa_memblock_stat *memblock_stat;
39 };
40
41 pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s) {
42 pa_mcalign *m;
43 assert(base);
44
45 m = pa_xnew(pa_mcalign, 1);
46
47 m->base = base;
48 pa_memchunk_reset(&m->leftover);
49 pa_memchunk_reset(&m->current);
50 m->memblock_stat = s;
51
52 return m;
53 }
54
55 void pa_mcalign_free(pa_mcalign *m) {
56 assert(m);
57
58 if (m->leftover.memblock)
59 pa_memblock_unref(m->leftover.memblock);
60
61 if (m->current.memblock)
62 pa_memblock_unref(m->current.memblock);
63
64 pa_xfree(m);
65 }
66
67 void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
68 assert(m);
69 assert(c);
70
71 assert(c->memblock);
72 assert(c->length > 0);
73
74 assert(!m->current.memblock);
75
76 /* Append to the leftover memory block */
77 if (m->leftover.memblock) {
78
79 /* Try to merge */
80 if (m->leftover.memblock == c->memblock &&
81 m->leftover.index + m->leftover.length == c->index) {
82
83 /* Merge */
84 m->leftover.length += c->length;
85
86 /* If the new chunk is larger than m->base, move it to current */
87 if (m->leftover.length >= m->base) {
88 m->current = m->leftover;
89 pa_memchunk_reset(&m->leftover);
90 }
91
92 } else {
93 size_t l;
94
95 /* We have to copy */
96 assert(m->leftover.length < m->base);
97 l = m->base - m->leftover.length;
98
99 if (l > c->length)
100 l = c->length;
101
102 /* Can we use the current block? */
103 pa_memchunk_make_writable(&m->leftover, m->memblock_stat, m->base);
104
105 memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l);
106 m->leftover.length += l;
107
108 assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length);
109
110 if (c->length > l) {
111 /* Save the remainder of the memory block */
112 m->current = *c;
113 m->current.index += l;
114 m->current.length -= l;
115 pa_memblock_ref(m->current.memblock);
116 }
117 }
118 } else {
119 /* Nothing to merge or copy, just store it */
120
121 if (c->length >= m->base)
122 m->current = *c;
123 else
124 m->leftover = *c;
125
126 pa_memblock_ref(c->memblock);
127 }
128 }
129
130 int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
131 assert(m);
132 assert(c);
133
134 /* First test if there's a leftover memory block available */
135 if (m->leftover.memblock) {
136 assert(m->leftover.length > 0 && m->leftover.length <= m->base);
137
138 /* The leftover memory block is not yet complete */
139 if (m->leftover.length < m->base)
140 return -1;
141
142 /* Return the leftover memory block */
143 *c = m->leftover;
144 pa_memchunk_reset(&m->leftover);
145
146 /* If the current memblock is too small move it the leftover */
147 if (m->current.memblock && m->current.length < m->base) {
148 m->leftover = m->current;
149 pa_memchunk_reset(&m->current);
150 }
151
152 return 0;
153 }
154
155 /* Now let's see if there is other data available */
156 if (m->current.memblock) {
157 size_t l;
158 assert(m->current.length >= m->base);
159
160 /* The length of the returned memory block */
161 l = m->current.length;
162 l /= m->base;
163 l *= m->base;
164 assert(l > 0);
165
166 /* Prepare the returned block */
167 *c = m->current;
168 pa_memblock_ref(c->memblock);
169 c->length = l;
170
171 /* Drop that from the current memory block */
172 assert(l <= m->current.length);
173 m->current.index += l;
174 m->current.length -= l;
175
176 /* In case the whole block was dropped ... */
177 if (m->current.length == 0)
178 pa_memblock_unref(m->current.memblock);
179 else {
180 /* Move the raimainder to leftover */
181 assert(m->current.length < m->base && !m->leftover.memblock);
182
183 m->leftover = m->current;
184 }
185
186 pa_memchunk_reset(&m->current);
187
188 return 0;
189 }
190
191 /* There's simply nothing */
192 return -1;
193
194 }
195
196 size_t pa_mcalign_csize(pa_mcalign *m, size_t l) {
197 assert(m);
198 assert(l > 0);
199
200 assert(!m->current.memblock);
201
202 if (m->leftover.memblock)
203 l += m->leftover.length;
204
205 return (l/m->base)*m->base;
206 }