2000-12-21 20:44:10 +00:00
|
|
|
/*
|
|
|
|
|
* Interval functions
|
|
|
|
|
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU Library General Public License as
|
|
|
|
|
* published by the Free Software Foundation; either version 2 of
|
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define INTERVAL_C
|
2000-12-29 15:00:53 +00:00
|
|
|
#define INTERVAL_INLINE
|
2000-12-21 20:44:10 +00:00
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <linux/asound.h>
|
|
|
|
|
#include "interval.h"
|
|
|
|
|
|
|
|
|
|
static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
|
|
|
|
|
{
|
|
|
|
|
*rem = *n % div;
|
|
|
|
|
*n /= div;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unsigned int div32(unsigned int a, unsigned int b,
|
|
|
|
|
unsigned int *r)
|
|
|
|
|
{
|
|
|
|
|
*r = a % b;
|
|
|
|
|
return a / b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unsigned int div_down(unsigned int a, unsigned int b)
|
|
|
|
|
{
|
|
|
|
|
return a / b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unsigned int div_up(unsigned int a, unsigned int b)
|
|
|
|
|
{
|
|
|
|
|
unsigned int r;
|
|
|
|
|
unsigned int q = div32(a, b, &r);
|
|
|
|
|
if (r)
|
|
|
|
|
++q;
|
|
|
|
|
return q;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unsigned int mul(unsigned int a, unsigned int b)
|
|
|
|
|
{
|
2001-01-15 11:06:53 +00:00
|
|
|
if (a == 0)
|
|
|
|
|
return 0;
|
2000-12-21 20:44:10 +00:00
|
|
|
if (div_down(UINT_MAX, a) < b)
|
|
|
|
|
return UINT_MAX;
|
|
|
|
|
return a * b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unsigned int add(unsigned int a, unsigned int b)
|
|
|
|
|
{
|
|
|
|
|
if (a >= UINT_MAX - b)
|
|
|
|
|
return UINT_MAX;
|
|
|
|
|
return a + b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unsigned int sub(unsigned int a, unsigned int b)
|
|
|
|
|
{
|
|
|
|
|
if (a > b)
|
|
|
|
|
return a - b;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline unsigned int muldiv32(unsigned int a, unsigned int b,
|
|
|
|
|
unsigned int c, unsigned int *r)
|
|
|
|
|
{
|
|
|
|
|
u_int64_t n = (u_int64_t) a * b;
|
|
|
|
|
div64_32(&n, c, r);
|
|
|
|
|
if (n >= UINT_MAX) {
|
|
|
|
|
*r = 0;
|
|
|
|
|
return UINT_MAX;
|
|
|
|
|
}
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-15 11:06:53 +00:00
|
|
|
int interval_refine_min(interval_t *i, unsigned int min, int openmin)
|
2000-12-21 20:44:10 +00:00
|
|
|
{
|
|
|
|
|
int changed = 0;
|
|
|
|
|
assert(!interval_empty(i));
|
|
|
|
|
if (i->min < min) {
|
|
|
|
|
i->min = min;
|
|
|
|
|
i->openmin = openmin;
|
|
|
|
|
changed = 1;
|
|
|
|
|
} else if (i->min == min && !i->openmin && openmin) {
|
|
|
|
|
i->openmin = 1;
|
|
|
|
|
changed = 1;
|
|
|
|
|
}
|
2001-01-15 11:06:53 +00:00
|
|
|
if (i->integer) {
|
2000-12-21 20:44:10 +00:00
|
|
|
if (i->openmin) {
|
|
|
|
|
i->min++;
|
|
|
|
|
i->openmin = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-12-23 10:14:15 +00:00
|
|
|
if (interval_checkempty(i)) {
|
2001-01-15 11:06:53 +00:00
|
|
|
interval_none(i);
|
2000-12-21 20:44:10 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-15 11:06:53 +00:00
|
|
|
int interval_refine_max(interval_t *i, unsigned int max, int openmax)
|
2000-12-21 20:44:10 +00:00
|
|
|
{
|
|
|
|
|
int changed = 0;
|
|
|
|
|
assert(!interval_empty(i));
|
|
|
|
|
if (i->max > max) {
|
|
|
|
|
i->max = max;
|
|
|
|
|
i->openmax = openmax;
|
|
|
|
|
changed = 1;
|
|
|
|
|
} else if (i->max == max && !i->openmax && openmax) {
|
|
|
|
|
i->openmax = 1;
|
|
|
|
|
changed = 1;
|
|
|
|
|
}
|
2001-01-15 11:06:53 +00:00
|
|
|
if (i->integer) {
|
2000-12-21 20:44:10 +00:00
|
|
|
if (i->openmax) {
|
|
|
|
|
i->max--;
|
|
|
|
|
i->openmax = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-12-23 10:14:15 +00:00
|
|
|
if (interval_checkempty(i)) {
|
2001-01-15 11:06:53 +00:00
|
|
|
interval_none(i);
|
2000-12-21 20:44:10 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* r <- v */
|
|
|
|
|
int interval_refine(interval_t *i, const interval_t *v)
|
|
|
|
|
{
|
|
|
|
|
int changed = 0;
|
|
|
|
|
assert(!interval_empty(i));
|
|
|
|
|
if (i->min < v->min) {
|
|
|
|
|
i->min = v->min;
|
|
|
|
|
i->openmin = v->openmin;
|
|
|
|
|
changed = 1;
|
|
|
|
|
} else if (i->min == v->min && !i->openmin && v->openmin) {
|
|
|
|
|
i->openmin = 1;
|
|
|
|
|
changed = 1;
|
|
|
|
|
}
|
|
|
|
|
if (i->max > v->max) {
|
|
|
|
|
i->max = v->max;
|
|
|
|
|
i->openmax = v->openmax;
|
|
|
|
|
changed = 1;
|
|
|
|
|
} else if (i->max == v->max && !i->openmax && v->openmax) {
|
|
|
|
|
i->openmax = 1;
|
|
|
|
|
changed = 1;
|
|
|
|
|
}
|
2001-01-15 11:06:53 +00:00
|
|
|
if (!i->integer && v->integer) {
|
|
|
|
|
i->integer = 1;
|
|
|
|
|
changed = 1;
|
|
|
|
|
}
|
|
|
|
|
if (i->integer) {
|
2000-12-21 20:44:10 +00:00
|
|
|
if (i->openmin) {
|
|
|
|
|
i->min++;
|
|
|
|
|
i->openmin = 0;
|
|
|
|
|
}
|
|
|
|
|
if (i->openmax) {
|
|
|
|
|
i->max--;
|
|
|
|
|
i->openmax = 0;
|
|
|
|
|
}
|
2001-01-15 11:06:53 +00:00
|
|
|
} else if (!i->openmin && !i->openmax && i->min == i->max)
|
|
|
|
|
i->integer = 1;
|
2000-12-23 10:14:15 +00:00
|
|
|
if (interval_checkempty(i)) {
|
2001-01-15 11:06:53 +00:00
|
|
|
interval_none(i);
|
2000-12-21 20:44:10 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int interval_refine_first(interval_t *i)
|
|
|
|
|
{
|
|
|
|
|
assert(!interval_empty(i));
|
2001-01-15 11:06:53 +00:00
|
|
|
if (interval_single(i))
|
2000-12-21 20:44:10 +00:00
|
|
|
return 0;
|
|
|
|
|
i->max = i->min;
|
|
|
|
|
i->openmax = i->openmin;
|
|
|
|
|
if (i->openmax)
|
|
|
|
|
i->max++;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int interval_refine_last(interval_t *i)
|
|
|
|
|
{
|
|
|
|
|
assert(!interval_empty(i));
|
2001-01-15 11:06:53 +00:00
|
|
|
if (interval_single(i))
|
2000-12-21 20:44:10 +00:00
|
|
|
return 0;
|
|
|
|
|
i->min = i->max;
|
|
|
|
|
i->openmin = i->openmax;
|
|
|
|
|
if (i->openmin)
|
|
|
|
|
i->min--;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int interval_refine_set(interval_t *i, unsigned int val)
|
|
|
|
|
{
|
|
|
|
|
interval_t t;
|
2001-01-15 11:06:53 +00:00
|
|
|
t.empty = 0;
|
|
|
|
|
t.min = t.max = val;
|
|
|
|
|
t.openmin = t.openmax = 0;
|
|
|
|
|
t.integer = 1;
|
2000-12-21 20:44:10 +00:00
|
|
|
return interval_refine(i, &t);
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-15 11:06:53 +00:00
|
|
|
void interval_add(const interval_t *a, const interval_t *b, interval_t *c)
|
2000-12-29 15:00:53 +00:00
|
|
|
{
|
2001-01-15 11:06:53 +00:00
|
|
|
if (a->empty || b->empty) {
|
|
|
|
|
interval_none(c);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
c->empty = 0;
|
|
|
|
|
c->min = add(a->min, b->min);
|
|
|
|
|
c->openmin = (a->openmin || b->openmin);
|
|
|
|
|
c->max = add(a->max, b->max);
|
|
|
|
|
c->openmax = (a->openmax || b->openmax);
|
|
|
|
|
c->integer = (a->integer && b->integer);
|
2000-12-29 15:00:53 +00:00
|
|
|
}
|
|
|
|
|
|
2001-01-15 11:06:53 +00:00
|
|
|
void interval_sub(const interval_t *a, const interval_t *b, interval_t *c)
|
2000-12-29 15:00:53 +00:00
|
|
|
{
|
2001-01-15 11:06:53 +00:00
|
|
|
if (a->empty || b->empty) {
|
|
|
|
|
interval_none(c);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
c->empty = 0;
|
|
|
|
|
c->min = sub(a->min, b->max);
|
|
|
|
|
c->openmin = (a->openmin || b->openmax);
|
|
|
|
|
c->max = add(a->max, b->min);
|
|
|
|
|
c->openmax = (a->openmax || b->openmin);
|
|
|
|
|
c->integer = (a->integer && b->integer);
|
2000-12-29 15:00:53 +00:00
|
|
|
}
|
|
|
|
|
|
2001-01-15 11:06:53 +00:00
|
|
|
void interval_mul(const interval_t *a, const interval_t *b, interval_t *c)
|
2000-12-21 20:44:10 +00:00
|
|
|
{
|
2001-01-15 11:06:53 +00:00
|
|
|
if (a->empty || b->empty) {
|
|
|
|
|
interval_none(c);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
c->empty = 0;
|
|
|
|
|
c->min = mul(a->min, b->min);
|
|
|
|
|
c->openmin = (a->openmin || b->openmin);
|
|
|
|
|
c->max = mul(a->max, b->max);
|
|
|
|
|
c->openmax = (a->openmax || b->openmax);
|
|
|
|
|
c->integer = (a->integer && b->integer);
|
2000-12-21 20:44:10 +00:00
|
|
|
}
|
|
|
|
|
|
2001-01-15 11:06:53 +00:00
|
|
|
void interval_div(const interval_t *a, const interval_t *b, interval_t *c)
|
2000-12-21 20:44:10 +00:00
|
|
|
{
|
|
|
|
|
unsigned int r;
|
2001-01-15 11:06:53 +00:00
|
|
|
if (a->empty || b->empty) {
|
|
|
|
|
interval_none(c);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
c->empty = 0;
|
|
|
|
|
c->min = div32(a->min, b->max, &r);
|
|
|
|
|
c->openmin = (r || a->openmin || b->openmax);
|
|
|
|
|
if (b->min > 0) {
|
|
|
|
|
c->max = div32(a->max, b->min, &r);
|
|
|
|
|
if (r) {
|
|
|
|
|
c->max++;
|
|
|
|
|
c->openmax = 1;
|
|
|
|
|
} else
|
|
|
|
|
c->openmax = (a->openmax || b->openmin);
|
|
|
|
|
} else {
|
|
|
|
|
c->max = UINT_MAX;
|
|
|
|
|
c->openmax = 0;
|
|
|
|
|
}
|
|
|
|
|
c->integer = 0;
|
2000-12-21 20:44:10 +00:00
|
|
|
}
|
|
|
|
|
|
2001-01-15 11:06:53 +00:00
|
|
|
/* a * b / c */
|
|
|
|
|
void interval_muldiv(const interval_t *a, const interval_t *b,
|
|
|
|
|
const interval_t *c, interval_t *d)
|
2000-12-21 20:44:10 +00:00
|
|
|
{
|
|
|
|
|
unsigned int r;
|
2001-01-15 11:06:53 +00:00
|
|
|
if (a->empty || b->empty || c->empty) {
|
|
|
|
|
interval_none(d);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
d->empty = 0;
|
|
|
|
|
d->min = muldiv32(a->min, b->min, c->max, &r);
|
|
|
|
|
d->openmin = (r || a->openmin || b->openmin || c->openmax);
|
|
|
|
|
d->max = muldiv32(a->max, b->max, c->min, &r);
|
2000-12-21 20:44:10 +00:00
|
|
|
if (r) {
|
2001-01-15 11:06:53 +00:00
|
|
|
d->max++;
|
|
|
|
|
d->openmax = 1;
|
2000-12-21 20:44:10 +00:00
|
|
|
} else
|
2001-01-15 11:06:53 +00:00
|
|
|
d->openmax = (a->openmax || b->openmax || c->openmin);
|
|
|
|
|
d->integer = 0;
|
2000-12-21 20:44:10 +00:00
|
|
|
}
|
|
|
|
|
|
2001-01-15 11:06:53 +00:00
|
|
|
/* a * b / k */
|
|
|
|
|
void interval_muldivk(const interval_t *a, const interval_t *b,
|
|
|
|
|
unsigned int k, interval_t *c)
|
2000-12-21 20:44:10 +00:00
|
|
|
{
|
|
|
|
|
unsigned int r;
|
2001-01-15 11:06:53 +00:00
|
|
|
if (a->empty || b->empty) {
|
|
|
|
|
interval_none(c);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
c->empty = 0;
|
|
|
|
|
c->min = muldiv32(a->min, b->min, k, &r);
|
|
|
|
|
c->openmin = (r || a->openmin || b->openmin);
|
|
|
|
|
c->max = muldiv32(a->max, b->max, k, &r);
|
2000-12-21 20:44:10 +00:00
|
|
|
if (r) {
|
2001-01-15 11:06:53 +00:00
|
|
|
c->max++;
|
|
|
|
|
c->openmax = 1;
|
2000-12-21 20:44:10 +00:00
|
|
|
} else
|
2001-01-15 11:06:53 +00:00
|
|
|
c->openmax = (a->openmax || b->openmax);
|
|
|
|
|
c->integer = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* a * k / b */
|
|
|
|
|
void interval_mulkdiv(const interval_t *a, unsigned int k,
|
|
|
|
|
const interval_t *b, interval_t *c)
|
|
|
|
|
{
|
|
|
|
|
unsigned int r;
|
|
|
|
|
if (a->empty || b->empty) {
|
|
|
|
|
interval_none(c);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
c->empty = 0;
|
|
|
|
|
c->min = muldiv32(a->min, k, b->max, &r);
|
|
|
|
|
c->openmin = (r || a->openmin || b->openmax);
|
|
|
|
|
if (b->min > 0) {
|
|
|
|
|
c->max = muldiv32(a->max, k, b->min, &r);
|
|
|
|
|
if (r) {
|
|
|
|
|
c->max++;
|
|
|
|
|
c->openmax = 1;
|
|
|
|
|
} else
|
|
|
|
|
c->openmax = (a->openmax || b->openmin);
|
|
|
|
|
} else {
|
|
|
|
|
c->max = UINT_MAX;
|
|
|
|
|
c->openmax = 0;
|
|
|
|
|
}
|
|
|
|
|
c->integer = 0;
|
2000-12-21 20:44:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void interval_print(const interval_t *i, FILE *fp)
|
|
|
|
|
{
|
2000-12-30 17:20:23 +00:00
|
|
|
if (interval_empty(i))
|
|
|
|
|
fprintf(fp, "NONE");
|
2001-01-15 11:06:53 +00:00
|
|
|
else if (i->min == 0 && i->openmin == 0 &&
|
|
|
|
|
i->max == UINT_MAX && i->openmax == 0)
|
|
|
|
|
fprintf(fp, "ALL");
|
2000-12-30 17:20:23 +00:00
|
|
|
else if (interval_single(i))
|
2000-12-21 20:44:10 +00:00
|
|
|
fprintf(fp, "%u", interval_value(i));
|
2000-12-30 17:20:23 +00:00
|
|
|
else
|
2000-12-21 20:44:10 +00:00
|
|
|
fprintf(fp, "%c%u %u%c",
|
|
|
|
|
i->openmin ? '(' : '[',
|
|
|
|
|
i->min, i->max,
|
|
|
|
|
i->openmax ? ')' : ']');
|
|
|
|
|
}
|