]> code.delx.au - pulseaudio/blob - src/polypcore/mcalign.c
4d7656250d469667cde7ac0e3b49faf2e47acb53
[pulseaudio] / src / polypcore / mcalign.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio 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 polypaudio 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 polypaudio; 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 "mcalign.h"
32 #include "xmalloc.h"
33
34 struct pa_mcalign {
35 size_t base;
36 pa_memchunk leftover, current;
37 pa_memblock_stat *memblock_stat;
38 };
39
40 pa_mcalign *pa_mcalign_new(size_t base, pa_memblock_stat *s) {
41 pa_mcalign *m;
42 assert(base);
43
44 m = pa_xnew(pa_mcalign, 1);
45 m->base = base;
46 pa_memchunk_reset(&m->leftover);
47 pa_memchunk_reset(&m->current);
48 m->memblock_stat = s;
49
50 return m;
51 }
52
53 void pa_mcalign_free(pa_mcalign *m) {
54 assert(m);
55
56 if (m->leftover.memblock)
57 pa_memblock_unref(m->leftover.memblock);
58
59 if (m->current.memblock)
60 pa_memblock_unref(m->current.memblock);
61
62 pa_xfree(m);
63 }
64
65 void pa_mcalign_push(pa_mcalign *m, const pa_memchunk *c) {
66 assert(m && c && c->memblock && c->length);
67
68 /* Append to the leftover memory block */
69 if (m->leftover.memblock) {
70 assert(!m->current.memblock);
71
72 /* Try to merge */
73 if (m->leftover.memblock == c->memblock &&
74 m->leftover.index + m->leftover.length == c->index) {
75
76 /* Merge */
77 m->leftover.length += c->length;
78
79 /* If the new chunk is larger than m->base, move it to current */
80 if (m->leftover.length >= m->base) {
81 m->current = m->leftover;
82 pa_memchunk_reset(&m->leftover);
83 }
84
85 } else {
86 size_t l;
87
88 /* We have to copy */
89 assert(m->leftover.length < m->base);
90 l = m->base - m->leftover.length;
91
92 if (l > c->length)
93 l = c->length;
94
95 /* Can we use the current block? */
96 pa_memchunk_make_writable(&m->leftover, m->memblock_stat, m->base);
97
98 memcpy((uint8_t*) m->leftover.memblock->data + m->leftover.index + m->leftover.length, (uint8_t*) c->memblock->data + c->index, l);
99 m->leftover.length += l;
100
101 assert(m->leftover.length <= m->base && m->leftover.length <= m->leftover.memblock->length);
102
103 if (c->length > l) {
104 /* Save the remainder of the memory block */
105 m->current = *c;
106 m->current.index += l;
107 m->current.length -= l;
108 pa_memblock_ref(m->current.memblock);
109 }
110 }
111 } else {
112 assert(!m->leftover.memblock && !m->current.memblock);
113
114 /* Nothing to merge or copy, just store it */
115
116 if (c->length >= m->base)
117 m->current = *c;
118 else
119 m->leftover = *c;
120
121 pa_memblock_ref(c->memblock);
122 }
123 }
124
125 int pa_mcalign_pop(pa_mcalign *m, pa_memchunk *c) {
126 assert(m && c);
127
128 /* First test if there's a leftover memory block available */
129 if (m->leftover.memblock) {
130 assert(m->leftover.length > 0 && m->leftover.length <= m->base);
131
132 /* The leftover memory block is not yet complete */
133 if (m->leftover.length < m->base)
134 return -1;
135
136 /* Return the leftover memory block */
137 *c = m->leftover;
138 pa_memchunk_reset(&m->leftover);
139
140 /* If the current memblock is too small move it the leftover */
141 if (m->current.memblock && m->current.length < m->base) {
142 m->leftover = m->current;
143 pa_memchunk_reset(&m->current);
144 }
145
146 return 0;
147 }
148
149 /* Now let's see if there is other data available */
150 if (m->current.memblock) {
151 size_t l;
152 assert(m->current.length >= m->base);
153
154 /* The length of the returned memory block */
155 l = m->current.length;
156 l /= m->base;
157 l *= m->base;
158 assert(l > 0);
159
160 /* Prepare the returned block */
161 *c = m->current;
162 pa_memblock_ref(c->memblock);
163 c->length = l;
164
165 /* Drop that from the current memory block */
166 assert(l <= m->current.length);
167 m->current.index += l;
168 m->current.length -= l;
169
170 /* In case the whole block was dropped ... */
171 if (m->current.length == 0)
172 pa_memblock_unref(m->current.memblock);
173 else {
174 /* Move the raimainder to leftover */
175 assert(m->current.length < m->base && !m->leftover.memblock);
176
177 m->leftover = m->current;
178 }
179
180 pa_memchunk_reset(&m->current);
181
182 return 0;
183 }
184
185 /* There's simply nothing */
186 return -1;
187
188 }