more work
[profile/ivi/pulseaudio.git] / src / memblockq.c
1 #include <stdio.h>
2 #include <assert.h>
3 #include <stdlib.h>
4
5 #include "memblockq.h"
6
7 struct memblock_list {
8     struct memblock_list *next;
9     struct memchunk chunk;
10 };
11
12 struct memblockq {
13     struct memblock_list *blocks, *blocks_tail;
14     unsigned n_blocks;
15     size_t total_length;
16     size_t maxlength;
17     size_t base;
18     size_t prebuf;
19 };
20
21
22 struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) {
23     struct memblockq* bq;
24     assert(maxlength && base);
25     
26     bq = malloc(sizeof(struct memblockq));
27     assert(bq);
28     bq->blocks = bq->blocks_tail = 0;
29     bq->n_blocks = 0;
30     bq->total_length = 0;
31     bq->base = base;
32     bq->maxlength = ((maxlength+base-1)/base)*base;
33     bq->prebuf = prebuf == (size_t) -1 ? bq->maxlength/2 : prebuf;
34     
35     if (bq->prebuf > bq->maxlength)
36         bq->prebuf = bq->maxlength;
37     
38     assert(bq->maxlength >= base);
39
40     return bq;
41 }
42
43 void memblockq_free(struct memblockq* bq) {
44     struct memblock_list *l;
45     assert(bq);
46
47     while ((l = bq->blocks)) {
48         bq->blocks = l->next;
49         memblock_unref(l->chunk.memblock);
50         free(l);
51     }
52     
53     free(bq);
54 }
55
56 void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta) {
57     struct memblock_list *q;
58     assert(bq && chunk && chunk->memblock && chunk->length);
59
60     q = malloc(sizeof(struct memblock_list));
61     assert(q);
62
63     q->chunk = *chunk;
64     memblock_ref(q->chunk.memblock);
65     assert(q->chunk.index+q->chunk.length <= q->chunk.memblock->length);
66     q->next = NULL;
67     
68     if (bq->blocks_tail)
69         bq->blocks_tail->next = q;
70     else
71         bq->blocks = q;
72     
73     bq->blocks_tail = q;
74
75     bq->n_blocks++;
76     bq->total_length += chunk->length;
77
78     memblockq_shorten(bq, bq->maxlength);
79 }
80
81 int memblockq_peek(struct memblockq* bq, struct memchunk *chunk) {
82     assert(bq && chunk);
83
84     if (!bq->blocks || bq->total_length < bq->prebuf)
85         return -1;
86
87     bq->prebuf = 0;
88
89     *chunk = bq->blocks->chunk;
90     memblock_ref(chunk->memblock);
91     return 0;
92 }
93
94 int memblockq_pop(struct memblockq* bq, struct memchunk *chunk) {
95     struct memblock_list *q;
96     
97     assert(bq && chunk);
98
99     if (!bq->blocks || bq->total_length < bq->prebuf)
100         return -1;
101
102     bq->prebuf = 0;
103
104     q = bq->blocks;
105     bq->blocks = bq->blocks->next;
106
107     *chunk = q->chunk;
108
109     bq->n_blocks--;
110     bq->total_length -= chunk->length;
111
112     free(q);
113     return 0;
114 }
115
116 void memblockq_drop(struct memblockq *bq, size_t length) {
117     assert(bq);
118
119     while (length > 0) {
120         size_t l = length;
121         assert(bq->blocks && bq->total_length >= length);
122         
123         if (l > bq->blocks->chunk.length)
124             l = bq->blocks->chunk.length;
125     
126         bq->blocks->chunk.index += l;
127         bq->blocks->chunk.length -= l;
128         bq->total_length -= l;
129         
130         if (bq->blocks->chunk.length == 0) {
131             struct memblock_list *q;
132             
133             q = bq->blocks;
134             bq->blocks = bq->blocks->next;
135             if (bq->blocks == NULL)
136                 bq->blocks_tail = NULL;
137             memblock_unref(q->chunk.memblock);
138             free(q);
139             
140             bq->n_blocks--;
141         }
142
143         length -= l;
144     }
145 }
146
147 void memblockq_shorten(struct memblockq *bq, size_t length) {
148     size_t l;
149     assert(bq);
150
151     if (bq->total_length <= length)
152         return;
153
154     fprintf(stderr, "Warning! memblockq_shorten()\n");
155     
156     l = bq->total_length - length;
157     l /= bq->base;
158     l *= bq->base;
159
160     memblockq_drop(bq, l);
161 }
162
163
164 void memblockq_empty(struct memblockq *bq) {
165     assert(bq);
166     memblockq_shorten(bq, 0);
167 }
168
169 int memblockq_is_readable(struct memblockq *bq) {
170     assert(bq);
171
172     return bq->total_length >= bq->prebuf;
173 }
174
175 int memblockq_is_writable(struct memblockq *bq, size_t length) {
176     assert(bq);
177
178     assert(length <= bq->maxlength);
179     return bq->total_length + length <= bq->maxlength;
180 }