Blame mmedian.c

Packit 9c3e7e
/**
Packit 9c3e7e
 * @file mmedian.c
Packit 9c3e7e
 * @note Copyright (C) 2013 Miroslav Lichvar <mlichvar@redhat.com>
Packit 9c3e7e
 *
Packit 9c3e7e
 * This program is free software; you can redistribute it and/or modify
Packit 9c3e7e
 * it under the terms of the GNU General Public License as published by
Packit 9c3e7e
 * the Free Software Foundation; either version 2 of the License, or
Packit 9c3e7e
 * (at your option) any later version.
Packit 9c3e7e
 *
Packit 9c3e7e
 * This program is distributed in the hope that it will be useful,
Packit 9c3e7e
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 9c3e7e
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 9c3e7e
 * GNU General Public License for more details.
Packit 9c3e7e
 *
Packit 9c3e7e
 * You should have received a copy of the GNU General Public License along
Packit 9c3e7e
 * with this program; if not, write to the Free Software Foundation, Inc.,
Packit 9c3e7e
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 9c3e7e
 */
Packit 9c3e7e
#include <stdlib.h>
Packit 9c3e7e
#include <string.h>
Packit 9c3e7e
Packit 9c3e7e
#include "mmedian.h"
Packit 9c3e7e
#include "filter_private.h"
Packit 9c3e7e
Packit 9c3e7e
struct mmedian {
Packit 9c3e7e
	struct filter filter;
Packit 9c3e7e
	int cnt;
Packit 9c3e7e
	int len;
Packit 9c3e7e
	int index;
Packit 9c3e7e
	/* Indices sorted by value. */
Packit 9c3e7e
	int *order;
Packit 9c3e7e
	/* Values stored in circular buffer. */
Packit 9c3e7e
	tmv_t *samples;
Packit 9c3e7e
};
Packit 9c3e7e
Packit 9c3e7e
static void mmedian_destroy(struct filter *filter)
Packit 9c3e7e
{
Packit 9c3e7e
	struct mmedian *m = container_of(filter, struct mmedian, filter);
Packit 9c3e7e
	free(m->order);
Packit 9c3e7e
	free(m->samples);
Packit 9c3e7e
	free(m);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static tmv_t mmedian_sample(struct filter *filter, tmv_t sample)
Packit 9c3e7e
{
Packit 9c3e7e
	struct mmedian *m = container_of(filter, struct mmedian, filter);
Packit 9c3e7e
	int i;
Packit 9c3e7e
Packit 9c3e7e
	m->samples[m->index] = sample;
Packit 9c3e7e
	if (m->cnt < m->len) {
Packit 9c3e7e
		m->cnt++;
Packit 9c3e7e
	} else {
Packit 9c3e7e
		/* Remove index of the replaced value from order. */
Packit 9c3e7e
		for (i = 0; i < m->cnt; i++)
Packit 9c3e7e
			if (m->order[i] == m->index)
Packit 9c3e7e
				break;
Packit 9c3e7e
		for (; i + 1 < m->cnt; i++)
Packit 9c3e7e
			m->order[i] = m->order[i + 1];
Packit 9c3e7e
	}
Packit 9c3e7e
Packit 9c3e7e
	/* Insert index of the new value to order. */
Packit 9c3e7e
	for (i = m->cnt - 1; i > 0; i--) {
Packit 9c3e7e
		if (tmv_cmp(m->samples[m->order[i - 1]],
Packit 9c3e7e
			    m->samples[m->index]) <= 0)
Packit 9c3e7e
			break;
Packit 9c3e7e
		m->order[i] = m->order[i - 1];
Packit 9c3e7e
	}
Packit 9c3e7e
	m->order[i] = m->index;
Packit 9c3e7e
Packit 9c3e7e
	m->index = (1 + m->index) % m->len;
Packit 9c3e7e
Packit 9c3e7e
	if (m->cnt % 2)
Packit 9c3e7e
		return m->samples[m->order[m->cnt / 2]];
Packit 9c3e7e
	else
Packit 9c3e7e
		return tmv_div(tmv_add(m->samples[m->order[m->cnt / 2 - 1]],
Packit 9c3e7e
				       m->samples[m->order[m->cnt / 2]]), 2);
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
static void mmedian_reset(struct filter *filter)
Packit 9c3e7e
{
Packit 9c3e7e
	struct mmedian *m = container_of(filter, struct mmedian, filter);
Packit 9c3e7e
	m->cnt = 0;
Packit 9c3e7e
	m->index = 0;
Packit 9c3e7e
}
Packit 9c3e7e
Packit 9c3e7e
struct filter *mmedian_create(int length)
Packit 9c3e7e
{
Packit 9c3e7e
	struct mmedian *m;
Packit 9c3e7e
Packit 9c3e7e
	if (length < 1)
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	m = calloc(1, sizeof(*m));
Packit 9c3e7e
	if (!m)
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	m->filter.destroy = mmedian_destroy;
Packit 9c3e7e
	m->filter.sample = mmedian_sample;
Packit 9c3e7e
	m->filter.reset = mmedian_reset;
Packit 9c3e7e
	m->order = calloc(1, length * sizeof(*m->order));
Packit 9c3e7e
	if (!m->order) {
Packit 9c3e7e
		free(m);
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	m->samples = calloc(1, length * sizeof(*m->samples));
Packit 9c3e7e
	if (!m->samples) {
Packit 9c3e7e
		free(m->order);
Packit 9c3e7e
		free(m);
Packit 9c3e7e
		return NULL;
Packit 9c3e7e
	}
Packit 9c3e7e
	m->len = length;
Packit 9c3e7e
	return &m->filter;
Packit 9c3e7e
}