avutil/fifo: delay addition of const from 78d3453c4a2efef9bc079e8f3458653beafcf990...
[ffmpeg.git] / libavutil / fifo.c
1 /*
2  * a very simple circular buffer FIFO implementation
3  * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4  * Copyright (c) 2006 Roman Shaposhnik
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 #include "avassert.h"
24 #include "common.h"
25 #include "fifo.h"
26
27 AVFifoBuffer *av_fifo_alloc(unsigned int size)
28 {
29     AVFifoBuffer *f = av_mallocz(sizeof(AVFifoBuffer));
30     if (!f)
31         return NULL;
32     f->buffer = av_malloc(size);
33     f->end    = f->buffer + size;
34     av_fifo_reset(f);
35     if (!f->buffer)
36         av_freep(&f);
37     return f;
38 }
39
40 void av_fifo_free(AVFifoBuffer *f)
41 {
42     if (f) {
43         av_freep(&f->buffer);
44         av_free(f);
45     }
46 }
47
48 void av_fifo_freep(AVFifoBuffer **f)
49 {
50     if (f) {
51         av_fifo_free(*f);
52         *f = NULL;
53     }
54 }
55
56 void av_fifo_reset(AVFifoBuffer *f)
57 {
58     f->wptr = f->rptr = f->buffer;
59     f->wndx = f->rndx = 0;
60 }
61
62 int av_fifo_size(FF_CONST_AVUTIL53 AVFifoBuffer *f)
63 {
64     return (uint32_t)(f->wndx - f->rndx);
65 }
66
67 int av_fifo_space(FF_CONST_AVUTIL53 AVFifoBuffer *f)
68 {
69     return f->end - f->buffer - av_fifo_size(f);
70 }
71
72 int av_fifo_realloc2(AVFifoBuffer *f, unsigned int new_size)
73 {
74     unsigned int old_size = f->end - f->buffer;
75
76     if (old_size < new_size) {
77         int len          = av_fifo_size(f);
78         AVFifoBuffer *f2 = av_fifo_alloc(new_size);
79
80         if (!f2)
81             return AVERROR(ENOMEM);
82         av_fifo_generic_read(f, f2->buffer, len, NULL);
83         f2->wptr += len;
84         f2->wndx += len;
85         av_free(f->buffer);
86         *f = *f2;
87         av_free(f2);
88     }
89     return 0;
90 }
91
92 int av_fifo_grow(AVFifoBuffer *f, unsigned int size)
93 {
94     unsigned int old_size = f->end - f->buffer;
95     if(size + (unsigned)av_fifo_size(f) < size)
96         return AVERROR(EINVAL);
97
98     size += av_fifo_size(f);
99
100     if (old_size < size)
101         return av_fifo_realloc2(f, FFMAX(size, 2*size));
102     return 0;
103 }
104
105 /* src must NOT be const as it can be a context for func that may need
106  * updating (like a pointer or byte counter) */
107 int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size,
108                           int (*func)(void *, void *, int))
109 {
110     int total = size;
111     uint32_t wndx= f->wndx;
112     uint8_t *wptr= f->wptr;
113
114     do {
115         int len = FFMIN(f->end - wptr, size);
116         if (func) {
117             if (func(src, wptr, len) <= 0)
118                 break;
119         } else {
120             memcpy(wptr, src, len);
121             src = (uint8_t *)src + len;
122         }
123 // Write memory barrier needed for SMP here in theory
124         wptr += len;
125         if (wptr >= f->end)
126             wptr = f->buffer;
127         wndx    += len;
128         size    -= len;
129     } while (size > 0);
130     f->wndx= wndx;
131     f->wptr= wptr;
132     return total - size;
133 }
134
135 int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size,
136                          void (*func)(void *, void *, int))
137 {
138 // Read memory barrier needed for SMP here in theory
139     do {
140         int len = FFMIN(f->end - f->rptr, buf_size);
141         if (func)
142             func(dest, f->rptr, len);
143         else {
144             memcpy(dest, f->rptr, len);
145             dest = (uint8_t *)dest + len;
146         }
147 // memory barrier needed for SMP here in theory
148         av_fifo_drain(f, len);
149         buf_size -= len;
150     } while (buf_size > 0);
151     return 0;
152 }
153
154 /** Discard data from the FIFO. */
155 void av_fifo_drain(AVFifoBuffer *f, int size)
156 {
157     av_assert2(av_fifo_size(f) >= size);
158     f->rptr += size;
159     if (f->rptr >= f->end)
160         f->rptr -= f->end - f->buffer;
161     f->rndx += size;
162 }
163
164 #ifdef TEST
165
166 int main(void)
167 {
168     /* create a FIFO buffer */
169     AVFifoBuffer *fifo = av_fifo_alloc(13 * sizeof(int));
170     int i, j, n;
171
172     /* fill data */
173     for (i = 0; av_fifo_space(fifo) >= sizeof(int); i++)
174         av_fifo_generic_write(fifo, &i, sizeof(int), NULL);
175
176     /* peek at FIFO */
177     n = av_fifo_size(fifo) / sizeof(int);
178     for (i = -n + 1; i < n; i++) {
179         int *v = (int *)av_fifo_peek2(fifo, i * sizeof(int));
180         printf("%d: %d\n", i, *v);
181     }
182     printf("\n");
183
184     /* read data */
185     for (i = 0; av_fifo_size(fifo) >= sizeof(int); i++) {
186         av_fifo_generic_read(fifo, &j, sizeof(int), NULL);
187         printf("%d ", j);
188     }
189     printf("\n");
190
191     av_fifo_free(fifo);
192
193     return 0;
194 }
195
196 #endif