util/DynamicFifoBuffer: new class replacing growing_fifo
This commit is contained in:
parent
9f3bead99f
commit
ad7302a032
@ -261,9 +261,9 @@ libutil_a_SOURCES = \
|
|||||||
src/util/RefCount.hxx \
|
src/util/RefCount.hxx \
|
||||||
src/util/fifo_buffer.c src/util/fifo_buffer.h \
|
src/util/fifo_buffer.c src/util/fifo_buffer.h \
|
||||||
src/util/FifoBuffer.hxx \
|
src/util/FifoBuffer.hxx \
|
||||||
|
src/util/DynamicFifoBuffer.hxx \
|
||||||
src/util/ConstBuffer.hxx \
|
src/util/ConstBuffer.hxx \
|
||||||
src/util/WritableBuffer.hxx \
|
src/util/WritableBuffer.hxx \
|
||||||
src/util/growing_fifo.c src/util/growing_fifo.h \
|
|
||||||
src/util/LazyRandomEngine.cxx src/util/LazyRandomEngine.hxx \
|
src/util/LazyRandomEngine.cxx src/util/LazyRandomEngine.hxx \
|
||||||
src/util/SliceBuffer.hxx \
|
src/util/SliceBuffer.hxx \
|
||||||
src/util/HugeAllocator.cxx src/util/HugeAllocator.hxx \
|
src/util/HugeAllocator.cxx src/util/HugeAllocator.hxx \
|
||||||
|
@ -23,15 +23,10 @@
|
|||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
#include "pcm/PcmBuffer.hxx"
|
#include "pcm/PcmBuffer.hxx"
|
||||||
#include "ConfigError.hxx"
|
#include "ConfigError.hxx"
|
||||||
|
#include "util/Manual.hxx"
|
||||||
|
#include "util/DynamicFifoBuffer.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "util/fifo_buffer.h"
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "util/growing_fifo.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <FLAC/stream_encoder.h>
|
#include <FLAC/stream_encoder.h>
|
||||||
|
|
||||||
@ -53,7 +48,7 @@ struct flac_encoder {
|
|||||||
* This buffer will hold encoded data from libFLAC until it is
|
* This buffer will hold encoded data from libFLAC until it is
|
||||||
* picked up with flac_encoder_read().
|
* picked up with flac_encoder_read().
|
||||||
*/
|
*/
|
||||||
struct fifo_buffer *output_buffer;
|
Manual<DynamicFifoBuffer<uint8_t>> output_buffer;
|
||||||
|
|
||||||
flac_encoder():encoder(flac_encoder_plugin) {}
|
flac_encoder():encoder(flac_encoder_plugin) {}
|
||||||
};
|
};
|
||||||
@ -140,7 +135,7 @@ flac_write_callback(gcc_unused const FLAC__StreamEncoder *fse,
|
|||||||
struct flac_encoder *encoder = (struct flac_encoder *) client_data;
|
struct flac_encoder *encoder = (struct flac_encoder *) client_data;
|
||||||
|
|
||||||
//transfer data to buffer
|
//transfer data to buffer
|
||||||
growing_fifo_append(&encoder->output_buffer, data, bytes);
|
encoder->output_buffer->Append((const uint8_t *)data, bytes);
|
||||||
|
|
||||||
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
||||||
}
|
}
|
||||||
@ -153,7 +148,7 @@ flac_encoder_close(Encoder *_encoder)
|
|||||||
FLAC__stream_encoder_delete(encoder->fse);
|
FLAC__stream_encoder_delete(encoder->fse);
|
||||||
|
|
||||||
encoder->expand_buffer.Clear();
|
encoder->expand_buffer.Clear();
|
||||||
fifo_buffer_free(encoder->output_buffer);
|
encoder->output_buffer.Destruct();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -195,7 +190,7 @@ flac_encoder_open(Encoder *_encoder, AudioFormat &audio_format, Error &error)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder->output_buffer = growing_fifo_new();
|
encoder->output_buffer.Construct(8192);
|
||||||
|
|
||||||
/* this immediately outputs data through callback */
|
/* this immediately outputs data through callback */
|
||||||
|
|
||||||
@ -304,18 +299,7 @@ flac_encoder_read(Encoder *_encoder, void *dest, size_t length)
|
|||||||
{
|
{
|
||||||
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
|
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
|
||||||
|
|
||||||
size_t max_length;
|
return encoder->output_buffer->Read((uint8_t *)dest, length);
|
||||||
const char *src = (const char *)
|
|
||||||
fifo_buffer_read(encoder->output_buffer, &max_length);
|
|
||||||
if (src == nullptr)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (length > max_length)
|
|
||||||
length = max_length;
|
|
||||||
|
|
||||||
memcpy(dest, src, length);
|
|
||||||
fifo_buffer_consume(encoder->output_buffer, length);
|
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
|
@ -20,21 +20,19 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "NullEncoderPlugin.hxx"
|
#include "NullEncoderPlugin.hxx"
|
||||||
#include "EncoderAPI.hxx"
|
#include "EncoderAPI.hxx"
|
||||||
#include "util/fifo_buffer.h"
|
#include "util/Manual.hxx"
|
||||||
extern "C" {
|
#include "util/DynamicFifoBuffer.hxx"
|
||||||
#include "util/growing_fifo.h"
|
|
||||||
}
|
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
struct NullEncoder final {
|
struct NullEncoder final {
|
||||||
Encoder encoder;
|
Encoder encoder;
|
||||||
|
|
||||||
struct fifo_buffer *buffer;
|
Manual<DynamicFifoBuffer<uint8_t>> buffer;
|
||||||
|
|
||||||
NullEncoder():encoder(null_encoder_plugin) {}
|
NullEncoder()
|
||||||
|
:encoder(null_encoder_plugin) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static Encoder *
|
static Encoder *
|
||||||
@ -58,7 +56,7 @@ null_encoder_close(Encoder *_encoder)
|
|||||||
{
|
{
|
||||||
NullEncoder *encoder = (NullEncoder *)_encoder;
|
NullEncoder *encoder = (NullEncoder *)_encoder;
|
||||||
|
|
||||||
fifo_buffer_free(encoder->buffer);
|
encoder->buffer.Destruct();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -68,7 +66,7 @@ null_encoder_open(Encoder *_encoder,
|
|||||||
gcc_unused Error &error)
|
gcc_unused Error &error)
|
||||||
{
|
{
|
||||||
NullEncoder *encoder = (NullEncoder *)_encoder;
|
NullEncoder *encoder = (NullEncoder *)_encoder;
|
||||||
encoder->buffer = growing_fifo_new();
|
encoder->buffer.Construct(8192);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +77,7 @@ null_encoder_write(Encoder *_encoder,
|
|||||||
{
|
{
|
||||||
NullEncoder *encoder = (NullEncoder *)_encoder;
|
NullEncoder *encoder = (NullEncoder *)_encoder;
|
||||||
|
|
||||||
growing_fifo_append(&encoder->buffer, data, length);
|
encoder->buffer->Append((const uint8_t *)data, length);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,17 +86,7 @@ null_encoder_read(Encoder *_encoder, void *dest, size_t length)
|
|||||||
{
|
{
|
||||||
NullEncoder *encoder = (NullEncoder *)_encoder;
|
NullEncoder *encoder = (NullEncoder *)_encoder;
|
||||||
|
|
||||||
size_t max_length;
|
return encoder->buffer->Read((uint8_t *)dest, length);
|
||||||
const void *src = fifo_buffer_read(encoder->buffer, &max_length);
|
|
||||||
if (src == nullptr)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (length > max_length)
|
|
||||||
length = max_length;
|
|
||||||
|
|
||||||
memcpy(dest, src, length);
|
|
||||||
fifo_buffer_consume(encoder->buffer, length);
|
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const EncoderPlugin null_encoder_plugin = {
|
const EncoderPlugin null_encoder_plugin = {
|
||||||
|
@ -21,10 +21,8 @@
|
|||||||
#include "WaveEncoderPlugin.hxx"
|
#include "WaveEncoderPlugin.hxx"
|
||||||
#include "EncoderAPI.hxx"
|
#include "EncoderAPI.hxx"
|
||||||
#include "system/ByteOrder.hxx"
|
#include "system/ByteOrder.hxx"
|
||||||
#include "util/fifo_buffer.h"
|
#include "util/Manual.hxx"
|
||||||
extern "C" {
|
#include "util/DynamicFifoBuffer.hxx"
|
||||||
#include "util/growing_fifo.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -33,7 +31,7 @@ struct WaveEncoder {
|
|||||||
Encoder encoder;
|
Encoder encoder;
|
||||||
unsigned bits;
|
unsigned bits;
|
||||||
|
|
||||||
struct fifo_buffer *buffer;
|
Manual<DynamicFifoBuffer<uint8_t>> buffer;
|
||||||
|
|
||||||
WaveEncoder():encoder(wave_encoder_plugin) {}
|
WaveEncoder():encoder(wave_encoder_plugin) {}
|
||||||
};
|
};
|
||||||
@ -128,9 +126,11 @@ wave_encoder_open(Encoder *_encoder,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder->buffer = growing_fifo_new();
|
encoder->buffer.Construct(8192);
|
||||||
wave_header *header = (wave_header *)
|
|
||||||
growing_fifo_write(&encoder->buffer, sizeof(*header));
|
auto range = encoder->buffer->Write();
|
||||||
|
assert(range.size >= sizeof(wave_header));
|
||||||
|
wave_header *header = (wave_header *)range.data;
|
||||||
|
|
||||||
/* create PCM wave header in initial buffer */
|
/* create PCM wave header in initial buffer */
|
||||||
fill_wave_header(header,
|
fill_wave_header(header,
|
||||||
@ -138,7 +138,8 @@ wave_encoder_open(Encoder *_encoder,
|
|||||||
encoder->bits,
|
encoder->bits,
|
||||||
audio_format.sample_rate,
|
audio_format.sample_rate,
|
||||||
(encoder->bits / 8) * audio_format.channels);
|
(encoder->bits / 8) * audio_format.channels);
|
||||||
fifo_buffer_append(encoder->buffer, sizeof(*header));
|
|
||||||
|
encoder->buffer->Append(sizeof(*header));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -148,7 +149,7 @@ wave_encoder_close(Encoder *_encoder)
|
|||||||
{
|
{
|
||||||
WaveEncoder *encoder = (WaveEncoder *)_encoder;
|
WaveEncoder *encoder = (WaveEncoder *)_encoder;
|
||||||
|
|
||||||
fifo_buffer_free(encoder->buffer);
|
encoder->buffer.Destruct();
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
@ -198,7 +199,7 @@ wave_encoder_write(Encoder *_encoder,
|
|||||||
{
|
{
|
||||||
WaveEncoder *encoder = (WaveEncoder *)_encoder;
|
WaveEncoder *encoder = (WaveEncoder *)_encoder;
|
||||||
|
|
||||||
uint8_t *dst = (uint8_t *)growing_fifo_write(&encoder->buffer, length);
|
uint8_t *dst = encoder->buffer->Write(length);
|
||||||
|
|
||||||
if (IsLittleEndian()) {
|
if (IsLittleEndian()) {
|
||||||
switch (encoder->bits) {
|
switch (encoder->bits) {
|
||||||
@ -230,7 +231,7 @@ wave_encoder_write(Encoder *_encoder,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fifo_buffer_append(encoder->buffer, length);
|
encoder->buffer->Append(length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,17 +240,7 @@ wave_encoder_read(Encoder *_encoder, void *dest, size_t length)
|
|||||||
{
|
{
|
||||||
WaveEncoder *encoder = (WaveEncoder *)_encoder;
|
WaveEncoder *encoder = (WaveEncoder *)_encoder;
|
||||||
|
|
||||||
size_t max_length;
|
return encoder->buffer->Read((uint8_t *)dest, length);
|
||||||
const void *src = fifo_buffer_read(encoder->buffer, &max_length);
|
|
||||||
if (src == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (length > max_length)
|
|
||||||
length = max_length;
|
|
||||||
|
|
||||||
memcpy(dest, src, length);
|
|
||||||
fifo_buffer_consume(encoder->buffer, length);
|
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
|
199
src/util/DynamicFifoBuffer.hxx
Normal file
199
src/util/DynamicFifoBuffer.hxx
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2013 Max Kellermann <max@duempel.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FIFO_BUFFER_HPP
|
||||||
|
#define FIFO_BUFFER_HPP
|
||||||
|
|
||||||
|
#include "WritableBuffer.hxx"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A first-in-first-out buffer: you can append data at the end, and
|
||||||
|
* read data from the beginning. This class automatically shifts the
|
||||||
|
* buffer as needed. It is not thread safe.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
class DynamicFifoBuffer {
|
||||||
|
public:
|
||||||
|
typedef size_t size_type;
|
||||||
|
typedef WritableBuffer<T> Range;
|
||||||
|
typedef typename Range::pointer_type pointer_type;
|
||||||
|
typedef typename Range::const_pointer_type const_pointer_type;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
size_type head, tail, capacity;
|
||||||
|
T *data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DynamicFifoBuffer(size_type _capacity)
|
||||||
|
:head(0), tail(0), capacity(_capacity),
|
||||||
|
data(new T[capacity]) {}
|
||||||
|
~DynamicFifoBuffer() {
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicFifoBuffer(const DynamicFifoBuffer &) = delete;
|
||||||
|
|
||||||
|
size_type GetCapacity() {
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Grow(size_type new_capacity) {
|
||||||
|
assert(new_capacity > capacity);
|
||||||
|
|
||||||
|
T *new_data = new T[new_capacity];
|
||||||
|
std::move(data + head, data + tail, new_data);
|
||||||
|
delete[] data;
|
||||||
|
data = new_data;
|
||||||
|
capacity = new_capacity;
|
||||||
|
tail -= head;
|
||||||
|
head = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear() {
|
||||||
|
head = tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEmpty() const {
|
||||||
|
return head == tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsFull() const {
|
||||||
|
return head == 0 && tail == capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares writing. Returns a buffer range which may be written.
|
||||||
|
* When you are finished, call append().
|
||||||
|
*/
|
||||||
|
Range Write() {
|
||||||
|
Shift();
|
||||||
|
return Range(data + tail, capacity - tail);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expands the tail of the buffer, after data has been written to
|
||||||
|
* the buffer returned by write().
|
||||||
|
*/
|
||||||
|
void Append(size_type n) {
|
||||||
|
assert(tail <= capacity);
|
||||||
|
assert(n <= capacity);
|
||||||
|
assert(tail + n <= capacity);
|
||||||
|
|
||||||
|
tail += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WantWrite(size_type n) {
|
||||||
|
if (tail + n <= capacity)
|
||||||
|
/* enough space after the tail */
|
||||||
|
return;
|
||||||
|
|
||||||
|
const size_type in_use = tail - head;
|
||||||
|
const size_type required_capacity = in_use + n;
|
||||||
|
if (capacity >= required_capacity) {
|
||||||
|
Shift();
|
||||||
|
} else {
|
||||||
|
size_type new_capacity = capacity;
|
||||||
|
do {
|
||||||
|
new_capacity <<= 1;
|
||||||
|
} while (new_capacity < required_capacity);
|
||||||
|
|
||||||
|
Grow(new_capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write data to the bfufer, growing it as needed. Returns a
|
||||||
|
* writable pointer.
|
||||||
|
*/
|
||||||
|
pointer_type Write(size_type n) {
|
||||||
|
WantWrite(n);
|
||||||
|
return data + tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append data to the buffer, growing it as needed.
|
||||||
|
*/
|
||||||
|
void Append(const_pointer_type p, size_type n) {
|
||||||
|
std::copy_n(p, n, Write(n));
|
||||||
|
Append(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a buffer range which may be read. The buffer pointer is
|
||||||
|
* writable, to allow modifications while parsing.
|
||||||
|
*/
|
||||||
|
Range Read() {
|
||||||
|
return Range(data + head, tail - head);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a chunk as consumed.
|
||||||
|
*/
|
||||||
|
void Consume(size_type n) {
|
||||||
|
assert(tail <= capacity);
|
||||||
|
assert(head <= tail);
|
||||||
|
assert(n <= tail);
|
||||||
|
assert(head + n <= tail);
|
||||||
|
|
||||||
|
head += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type Read(pointer_type p, size_type n) {
|
||||||
|
auto range = Read();
|
||||||
|
if (n > range.size)
|
||||||
|
n = range.size;
|
||||||
|
std::copy_n(range.data, n, p);
|
||||||
|
Consume(n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Shift() {
|
||||||
|
if (head == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert(head <= capacity);
|
||||||
|
assert(tail <= capacity);
|
||||||
|
assert(tail >= head);
|
||||||
|
|
||||||
|
std::move(data + head, data + tail, data);
|
||||||
|
|
||||||
|
tail -= head;
|
||||||
|
head = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2003-2011 The Music Player Daemon Project
|
|
||||||
* http://www.musicpd.org
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the
|
|
||||||
* distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
||||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "growing_fifo.h"
|
|
||||||
#include "fifo_buffer.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Align buffer sizes at 8 kB boundaries. Must be a power of two.
|
|
||||||
*/
|
|
||||||
static const size_t GROWING_FIFO_ALIGN = 8192;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Align the specified size to the next #GROWING_FIFO_ALIGN boundary.
|
|
||||||
*/
|
|
||||||
static size_t
|
|
||||||
align(size_t size)
|
|
||||||
{
|
|
||||||
return ((size - 1) | (GROWING_FIFO_ALIGN - 1)) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fifo_buffer *
|
|
||||||
growing_fifo_new(void)
|
|
||||||
{
|
|
||||||
return fifo_buffer_new(GROWING_FIFO_ALIGN);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
growing_fifo_write(struct fifo_buffer **buffer_p, size_t length)
|
|
||||||
{
|
|
||||||
assert(buffer_p != NULL);
|
|
||||||
|
|
||||||
struct fifo_buffer *buffer = *buffer_p;
|
|
||||||
assert(buffer != NULL);
|
|
||||||
|
|
||||||
size_t max_length;
|
|
||||||
void *p = fifo_buffer_write(buffer, &max_length);
|
|
||||||
if (p != NULL && max_length >= length)
|
|
||||||
return p;
|
|
||||||
|
|
||||||
/* grow */
|
|
||||||
size_t new_size = fifo_buffer_available(buffer) + length;
|
|
||||||
assert(new_size > fifo_buffer_capacity(buffer));
|
|
||||||
*buffer_p = buffer = fifo_buffer_realloc(buffer, align(new_size));
|
|
||||||
|
|
||||||
/* try again */
|
|
||||||
p = fifo_buffer_write(buffer, &max_length);
|
|
||||||
assert(p != NULL);
|
|
||||||
assert(max_length >= length);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
growing_fifo_append(struct fifo_buffer **buffer_p,
|
|
||||||
const void *data, size_t length)
|
|
||||||
{
|
|
||||||
void *p = growing_fifo_write(buffer_p, length);
|
|
||||||
memcpy(p, data, length);
|
|
||||||
fifo_buffer_append(*buffer_p, length);
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2003-2011 The Music Player Daemon Project
|
|
||||||
* http://www.musicpd.org
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* - Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* - Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the
|
|
||||||
* distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
||||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
*
|
|
||||||
* Helper functions for our FIFO buffer library (fifo_buffer.h) that
|
|
||||||
* allows growing the buffer on demand.
|
|
||||||
*
|
|
||||||
* This library is not thread safe.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MPD_GROWING_FIFO_H
|
|
||||||
#define MPD_GROWING_FIFO_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
struct fifo_buffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate a new #fifo_buffer with the default size.
|
|
||||||
*/
|
|
||||||
struct fifo_buffer *
|
|
||||||
growing_fifo_new(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares writing to the buffer, see fifo_buffer_write() for
|
|
||||||
* details. The difference is that this function will automatically
|
|
||||||
* grow the buffer if it is too small.
|
|
||||||
*
|
|
||||||
* The caller is responsible for limiting the capacity of the buffer.
|
|
||||||
*
|
|
||||||
* @param length the number of bytes that will be written
|
|
||||||
* @return a pointer to the end of the buffer (will not be NULL)
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
growing_fifo_write(struct fifo_buffer **buffer_p, size_t length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper function that combines growing_fifo_write(), memcpy(),
|
|
||||||
* fifo_buffer_append().
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
growing_fifo_append(struct fifo_buffer **buffer_p,
|
|
||||||
const void *data, size_t length);
|
|
||||||
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue
Block a user