/* GENIUS Calculator
* Copyright (C) 1997-2007 Jiri (George) Lebl
*
* Author: George Lebl
*
* This file is part of Genius.
*
* Genius is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "config.h"
#include
#include
#include "structs.h"
#include "eval.h"
#include "matrix.h"
/*implement the inline functions*/
#undef G_INLINE_FUNC
#undef G_CAN_INLINE
#define G_INLINE_FUNC extern
#define G_CAN_INLINE 1
#include "matrixw.h"
/* #define MATRIX_DEBUG 1 */
/* we cast matrix to this structure to stuff it onto
the free matrix list, we could just cast it to a
pointer but this gives the impression of being
cleaner*/
typedef struct _GelMatrixWFreeList GelMatrixWFreeList;
struct _GelMatrixWFreeList {
GelMatrixWFreeList *next;
};
static void internal_make_private (GelMatrixW *m, int w, int h);
static GelMatrixWFreeList *free_matrices = NULL;
#define NEW_MATRIX(m) \
if (free_matrices == NULL) { \
m = g_new (GelMatrixW, 1); \
} else { \
m = (GelMatrixW *)free_matrices; \
free_matrices = free_matrices->next; \
}
GelETree *the_zero = NULL;
/*free a matrix*/
static void
internal_matrix_free (GelMatrix *m)
{
int i, j;
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
if (m->use == 1) {
#ifdef MATRIX_DEBUG
/*debug*/printf ("ACTUALLY FREE\n");
#endif
for (i = 0; i < m->width; i++) {
for (j = 0; j < m->height; j++) {
GelETree *t = gel_matrix_index (m, i, j);
if (t != NULL)
gel_freetree (t);
}
}
gel_matrix_free (m);
} else {
m->use--;
}
}
static int
getmax (const int *reg, int len)
{
int max = 0;
int i;
for (i = 0; i < len; i++)
if (reg[i] > max)
max = reg[i];
return max;
}
/* This should be streamlined */
static inline gboolean
has_duplicates (const int *reg, int l)
{
int i, ii;
if (reg == NULL)
return FALSE;
for (i = 0; i < l; i++) {
for (ii = i+1; ii < l; ii++) {
if (reg[ii] == reg[i])
return TRUE;
}
}
return FALSE;
}
/*make new matrix*/
GelMatrixW *
gel_matrixw_new(void)
{
GelMatrixW *m;
NEW_MATRIX (m);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
m->m = gel_matrix_new();
m->m->use = 1;
/* clear caches as we're gonna mess with this matrix */
m->cached_value_only = 0;
m->cached_value_only_real = 0;
m->cached_value_only_rational = 0;
m->cached_value_only_integer = 0;
m->cached_value_or_bool_only = 0;
m->rref = 0;
m->tr = 0;
m->regx = NULL;
m->regy = NULL;
m->regw = m->m->width;
m->regh = m->m->height;
if (the_zero == NULL)
the_zero = gel_makenum_ui (0);
return m;
}
GelMatrixW *
gel_matrixw_new_with_matrix(GelMatrix *mat)
{
GelMatrixW *m;
NEW_MATRIX (m);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
m->m = mat;
m->m->use++;
/* clear caches as we're gonna mess with this matrix */
m->cached_value_only = 0;
m->cached_value_only_real = 0;
m->cached_value_only_rational = 0;
m->cached_value_only_integer = 0;
m->cached_value_or_bool_only = 0;
m->rref = 0;
m->tr = 0;
m->regx = NULL;
m->regy = NULL;
m->regw = m->m->width;
m->regh = m->m->height;
if (the_zero == NULL)
the_zero = gel_makenum_ui (0);
return m;
}
/* neww and newh do not actually guarantee that size,
* also note that these sizes are after transpose
* they just prevent useless copying*/
static void
make_us_a_copy (GelMatrixW *m, int neww, int newh)
{
GelMatrix *old;
int i,j;
int w,h;
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
if (m->m->use == 1)
return;
old = m->m;
m->m = gel_matrix_new();
m->m->use = 1;
gel_matrix_set_size (m->m, neww, newh, TRUE /* padding */);
w = MIN (neww, m->regw);
h = MIN (newh, m->regh);
for (i = 0; i < w; i++) {
for(j = 0; j < h; j++) {
int mi = m->regx ? m->regx[i] : i;
int mj = m->regy ? m->regy[j] : j;
GelETree *t = gel_matrix_index (old, mi, mj);
#ifdef MATRIX_DEBUG
printf ("(%d,%d) = (%d,%d)\n", i, j,mi, mj);
#endif
gel_matrix_index (m->m, i, j) = copynode (t);
}
}
g_free (m->regx);
m->regx = NULL;
g_free (m->regy);
m->regy = NULL;
m->regw = w;
m->regh = h;
old->use--;
}
/* This assumes that use > 1 and transpose has been dealt with */
static void
copy_with_region (GelMatrixW *m, int *regx, int *regy, int w, int h)
{
GelMatrix *old;
int i, j;
int cw, ch;
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
g_assert (m->m->use > 1);
old = m->m;
m->m = gel_matrix_new();
m->m->use = 1;
gel_matrix_set_size (m->m, w, h, TRUE /* padding */);
cw = MIN (w, m->regw);
ch = MIN (h, m->regh);
for (i = 0; i < cw; i++) {
for(j = 0; j < ch; j++) {
int mi = m->regx ? m->regx[regx[i]] : regx[i];
int mj = m->regy ? m->regy[regy[j]] : regy[j];
GelETree *t = gel_matrix_index (old, mi, mj);
gel_matrix_index (m->m, i, j) = copynode (t);
}
}
g_free (m->regx);
m->regx = NULL;
g_free (m->regy);
m->regy = NULL;
m->regw = w;
m->regh = h;
old->use--;
}
/* This assumes that use > 1 and transpose has been dealt with */
static void
copy_internal_region (GelMatrixW *m, int w, int h)
{
GelMatrix *old;
int i, j;
int cw, ch;
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
g_assert (m->m->use > 1);
old = m->m;
m->m = gel_matrix_new();
m->m->use = 1;
gel_matrix_set_size (m->m, w, h, TRUE /* padding */);
cw = MIN (w, m->regw);
ch = MIN (h, m->regh);
for (i = 0; i < cw; i++) {
for(j = 0; j < ch; j++) {
int mi = m->regx ? m->regx[i] : i;
int mj = m->regy ? m->regy[j] : j;
GelETree *t = gel_matrix_index (old, mi, mj);
if (t != NULL &&
(t->type != VALUE_NODE ||
! mpw_exact_zero_p (t->val.value)))
gel_matrix_index (m->m, i, j) = copynode (t);
}
}
g_free (m->regx);
m->regx = NULL;
g_free (m->regy);
m->regy = NULL;
m->regw = w;
m->regh = h;
old->use--;
}
/* This ensures the size of the matrix,
* sizes are after transpose,
* make sure to work with a copy,
* note that this whacks regx and regy */
static void
ensure_at_least_size (GelMatrixW *m, int w, int h)
{
g_assert (m->m->use == 1);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
if (m->regx == NULL && m->regy == NULL) {
gel_matrix_set_at_least_size (m->m, w, h);
if (w > m->regw)
m->regw = w;
if (h > m->regh)
m->regh = h;
} else {
/* FIXME: somewhat evil, but I think this is a degenerate case,
* we will have regions when reffering to other matrices, not
* really when we own a matrix I think. At least in casual use */
GelMatrix *old;
int i,j;
int nw,nh;
old = m->m;
m->m = gel_matrix_new();
m->m->use = 1;
gel_matrix_set_size (m->m, w, h, TRUE /* padding */);
nw = MIN (w, m->regw);
nh = MIN (h, m->regh);
for (i = 0; i < nw; i++) {
for (j = 0; j < nh; j++) {
int mi = m->regx ? m->regx[i] : i;
int mj = m->regy ? m->regy[j] : j;
GelETree *t = gel_matrix_index (old, mi, mj);
if (t != NULL) {
gel_matrix_index (m->m,i,j) = t;
gel_matrix_index (old, mi, mj) = NULL;
}
}
}
for (i = 0; i < old->width; i++) {
for (j = 0; j < old->height; j++) {
GelETree *t = gel_matrix_index (old,i,j);
if (t != NULL)
gel_freetree (t);
}
}
gel_matrix_free (old);
g_free (m->regx);
m->regx = NULL;
g_free (m->regy);
m->regy = NULL;
m->regw = w;
m->regh = h;
}
}
/*set size of a matrix*/
void
gel_matrixw_set_size (GelMatrixW *m, int nwidth, int nheight)
{
int width, height;
g_return_if_fail (m != NULL);
g_return_if_fail (nwidth >= 0);
g_return_if_fail (nheight >= 0);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
if (m->tr) {
width = nheight;
height = nwidth;
} else {
width = nwidth;
height = nheight;
}
/* we're changing things so make sure we don't consider it rref
* anymore */
m->rref = 0;
if (m->regw >= width &&
m->regh >= height) {
/*if we're the sole owner, we'll have to zero out some things*/
if (m->m->use == 1) {
int i, j;
/* if duplicates are found just do some
* copying */
if (has_duplicates (m->regx, m->regw) ||
has_duplicates (m->regy, m->regh)) {
GelMatrix *old = m->m;
#ifdef MATRIX_DEBUG
/*debug*/printf ("HAS_DUPLICATES\n");
#endif
/* evil */ old->use ++;
copy_internal_region (m, width, height);
internal_matrix_free (old);
return;
}
for (i = width; i < m->regw; i++) {
for (j = 0; j < m->regh; j++) {
int mi = m->regx ? m->regx[i] : i;
int mj = m->regy ? m->regy[j] : j;
if (gel_matrix_index (m->m, mi, mj) != NULL) {
gel_freetree(gel_matrix_index(m->m,mi,mj));
gel_matrix_index(m->m,mi,mj)=NULL;
}
}
}
for (i = 0; i < width; i++) {
for (j = height; j < m->regh; j++) {
int mi = m->regx ? m->regx[i] : i;
int mj = m->regy ? m->regy[j] : j;
if (gel_matrix_index (m->m, mi, mj) != NULL) {
gel_freetree(gel_matrix_index(m->m,mi,mj));
gel_matrix_index(m->m,mi,mj)=NULL;
}
}
}
}
m->regw = width;
m->regh = height;
} else if (m->m->use > 1) {
/* since the use is greater than 1, we WILL get a copy of
* this matrix at the right size */
internal_make_private (m, width, height);
g_assert (m->m->use == 1);
} else /* m->m->use == 1 */{
ensure_at_least_size (m, width, height);
gel_matrixw_set_size (m, nwidth, nheight);
}
}
/*set the size of the matrix to be at least this*/
void
gel_matrixw_set_at_least_size (GelMatrixW *m, int width, int height)
{
g_return_if_fail (m != NULL);
g_return_if_fail (width >= 0);
g_return_if_fail (height >= 0);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
if (m->tr) {
int tmp = width;
width = height;
height = tmp;
}
if (width > m->regw || height > m->regh) {
/* FIXME: this may be a bit inefficent */
gel_matrixw_make_private (m);
make_us_a_copy (m, MAX (width, m->regw),MAX (height, m->regh));
ensure_at_least_size (m, width, height);
}
}
/*set element*/
void
gel_matrixw_set_element (GelMatrixW *m, int x, int y, gpointer data)
{
GelETree *t;
g_return_if_fail (m != NULL);
g_return_if_fail (x >= 0);
g_return_if_fail (y >= 0);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
if (m->tr)
internal_make_private (m, MAX(m->regh, y+1), MAX(m->regw, x+1));
else
internal_make_private (m, MAX(m->regw, x+1), MAX(m->regh, y+1));
gel_matrixw_set_at_least_size (m, x+1, y+1);
t = gel_matrixw_get_index (m, x, y);
if (t != NULL)
gel_freetree (t);
gel_matrixw_set_index (m, x, y) = data;
}
/*set vector element*/
void
gel_matrixw_set_velement (GelMatrixW *m, int i, gpointer data)
{
GelETree *t;
int x, y;
g_return_if_fail (m != NULL);
g_return_if_fail (i >= 0);
if (m->tr) {
if (m->regw == 1) {
x = 0;
y = i;
} else {
x = i % m->regh;
y = i / m->regh;
}
internal_make_private (m, MAX(m->regh, y+1), MAX(m->regw, x+1));
} else {
if (m->regh == 1) {
x = i;
y = 0;
} else {
x = i % m->regw;
y = i / m->regw;
}
internal_make_private (m, MAX(m->regw, x+1), MAX(m->regh, y+1));
}
gel_matrixw_set_at_least_size (m, x+1, y+1);
t = gel_matrixw_get_index (m, x, y);
if (t != NULL)
gel_freetree (t);
gel_matrixw_set_index (m, x, y) = data;
}
/*make sure it's in range first!*/
GelMatrixW *
gel_matrixw_get_region (GelMatrixW *m, int *regx, int *regy, int w, int h)
{
GelMatrixW *new;
g_return_val_if_fail (m != NULL, NULL);
g_return_val_if_fail (regx != NULL, NULL);
g_return_val_if_fail (regy != NULL, NULL);
g_return_val_if_fail (w >= 1, NULL);
g_return_val_if_fail (h >= 1, NULL);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
if (m->tr) {
int t;
int *tmp = regx;
regx = regy;
regy = tmp;
t = w;
w = h;
h = t;
}
new = gel_matrixw_copy (m);
/* we're changing things so make sure we don't consider it rref
* anymore */
new->rref = 0;
if (getmax (regx, w) >= new->regw ||
getmax (regy, h) >= new->regh) {
/* FIXME: maybe we can whack a bit of region stuff here,
* instead of always copying, we sometimes don't have to
* I think */
copy_with_region (new, regx, regy, w, h);
return new;
}
if (new->regx == NULL) {
new->regx = g_new (int, w);
memcpy (new->regx, regx, sizeof(int)*w);
} else {
int i;
int *nregx = g_new (int, w);
for (i = 0; i < w; i++)
nregx[i] = new->regx[regx[i]];
g_free (new->regx);
new->regx = nregx;
}
new->regw = w;
if (new->regy == NULL) {
new->regy = g_new (int, h);
memcpy (new->regy, regy, sizeof(int)*h);
} else {
int i;
int *nregy = g_new (int, h);
for (i = 0; i < h; i++)
nregy[i] = new->regy[regy[i]];
g_free (new->regy);
new->regy = nregy;
}
new->regh = h;
return new;
}
/*make sure it's in range first!*/
GelMatrixW *
gel_matrixw_get_vregion (GelMatrixW *m, int *reg, int len)
{
GelMatrix *vec;
int i;
g_return_val_if_fail (m != NULL, NULL);
g_return_val_if_fail (reg != NULL, NULL);
g_return_val_if_fail (len >= 1, NULL);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
vec = gel_matrix_new ();
gel_matrix_set_size (vec, len, 1, FALSE /* padding */);
for (i = 0; i < len; i++) {
GelETree *t = gel_matrixw_get_vindex (m, reg[i]);
if (t != NULL)
t = copynode (t);
gel_matrix_index (vec, i, 0) = t;
}
return gel_matrixw_new_with_matrix (vec);
}
void
gel_matrixw_set_region(GelMatrixW *m, GelMatrixW *src,
int *destx, int *desty,
int w, int h)
{
int i, j;
int xmax, ymax;
g_return_if_fail (m != NULL);
g_return_if_fail (src != NULL);
g_return_if_fail (destx != NULL);
g_return_if_fail (desty != NULL);
g_return_if_fail (w >= 0);
g_return_if_fail (h >= 0);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
if (m->tr) {
int t;
int *tmp = destx;
destx = desty;
desty = tmp;
t = w;
w = h;
h = t;
}
xmax = getmax (destx, w);
ymax = getmax (desty, h);
/* FIXME: we will copy some nodes we don't need to copy
* as we will free them just below */
internal_make_private (m, MAX (xmax+1, m->regw), MAX (ymax+1, m->regh));
ensure_at_least_size (m, xmax+1, ymax+1);
/* assume that's what ensure/make_us_a_copy does */
g_assert (m->regx == NULL && m->regy == NULL);
for (i = 0; i < w; i++) {
for ( j = 0; j < h; j++) {
int si, sj;
GelETree *t = gel_matrix_index (m->m, destx[i], desty[j]);
if (m->tr == src->tr) {
si = i;
sj = j;
} else {
si = j;
sj = i;
}
if (si >= src->regw ||
sj >= src->regh) {
gel_matrix_index (m->m, destx[i], desty[j]) = NULL;
} else {
gel_matrix_index (m->m, destx[i], desty[j]) = copynode
(gel_matrix_index (src->m,
src->regx ? src->regx[si] : si,
src->regy ? src->regy[sj] : sj));
}
if (t != NULL) gel_freetree (t);
}
}
}
void
gel_matrixw_set_region_etree (GelMatrixW *m, GelETree *src,
int *destx, int *desty,
int w, int h)
{
int i, j;
int xmax, ymax;
g_return_if_fail (m != NULL);
g_return_if_fail (src != NULL);
g_return_if_fail (destx != NULL);
g_return_if_fail (desty != NULL);
g_return_if_fail (w >= 0);
g_return_if_fail (h >= 0);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
if (m->tr) {
int t;
int *tmp = destx;
destx = desty;
desty = tmp;
t = w;
w = h;
h = t;
}
xmax = getmax (destx, w);
ymax = getmax (desty, h);
internal_make_private (m, MAX (xmax+1, m->regw), MAX (ymax+1, m->regh));
ensure_at_least_size (m, xmax+1, ymax+1);
/* assume that's what ensure/make_us_a_copy does */
g_assert (m->regx == NULL && m->regy == NULL);
for (i = 0; i < w; i++) {
for ( j = 0; j < h; j++) {
GelETree *t = gel_matrix_index (m->m, destx[i], desty[j]);
gel_matrix_index (m->m, destx[i], desty[j]) = copynode (src);
if (t != NULL)
gel_freetree (t);
}
}
}
/*copy a matrix*/
GelMatrixW *
gel_matrixw_copy (GelMatrixW *source)
{
GelMatrixW *m;
g_return_val_if_fail (source != NULL, NULL);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
NEW_MATRIX (m);
memcpy (m, source, sizeof (GelMatrixW));
if (m->regx != NULL) {
m->regx = g_new (int, m->regw);
memcpy (m->regx, source->regx, m->regw * sizeof (int));
}
if (m->regy != NULL) {
m->regy = g_new (int, m->regh);
memcpy (m->regy, source->regy, m->regh * sizeof (int));
}
m->m->use++;
return m;
}
GelMatrixW *
gel_matrixw_rowsof (GelMatrixW *source)
{
GelMatrix *mm;
int i, width, height;
int *reg;
g_return_val_if_fail (source != NULL, NULL);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
width = gel_matrixw_width (source);
height = gel_matrixw_height (source);
mm = gel_matrix_new ();
gel_matrix_set_size (mm, 1, height, FALSE /* padding */);
reg = g_new (int, width);
for (i = 0; i < width; i++)
reg[i] = i;
for (i = 0; i < height; i++) {
GelETree *n;
GET_NEW_NODE (n);
n->type = MATRIX_NODE;
n->mat.matrix = gel_matrixw_get_region (source, reg, &i, width, 1);
gel_matrix_index (mm, 0, i) = n;
}
g_free (reg);
return gel_matrixw_new_with_matrix (mm);
}
GelMatrixW *
gel_matrixw_columnsof (GelMatrixW *source)
{
GelMatrix *mm;
int i, width, height;
int *reg;
g_return_val_if_fail (source != NULL, NULL);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
width = gel_matrixw_width (source);
height = gel_matrixw_height (source);
mm = gel_matrix_new ();
gel_matrix_set_size (mm, width, 1, FALSE /* padding */);
reg = g_new (int, height);
for (i = 0; i < height; i++)
reg[i] = i;
for (i = 0; i < width; i++) {
GelETree *n;
GET_NEW_NODE (n);
n->type = MATRIX_NODE;
n->mat.matrix = gel_matrixw_get_region (source, &i, reg, 1, height);
n->mat.quoted = 0;
gel_matrix_index (mm, i, 0) = n;
}
g_free (reg);
return gel_matrixw_new_with_matrix (mm);
}
GelMatrixW *
gel_matrixw_diagonalof (GelMatrixW *source)
{
GelMatrix *mm;
int i, width, height;
int len;
g_return_val_if_fail (source != NULL, NULL);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
width = gel_matrixw_width (source);
height = gel_matrixw_height (source);
len = MIN(width,height);
mm = gel_matrix_new ();
gel_matrix_set_size (mm, 1, len, FALSE /* padding */);
for (i = 0; i < len; i++) {
GelETree *n = gel_matrixw_get_index (source, i, i);
if (n != NULL)
n = copynode (n);
gel_matrix_index (mm, 0, i) = n;
}
return gel_matrixw_new_with_matrix (mm);
}
/*transpose a matrix*/
GelMatrixW *
gel_matrixw_transpose(GelMatrixW *m)
{
GelMatrixW *new;
g_return_val_if_fail(m != NULL,NULL);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
new = gel_matrixw_copy(m);
/* we're changing things so make sure we don't consider it rref
* anymore */
new->rref = 0;
new->tr = !new->tr;
return new;
}
/*make private copy of the GelMatrix*/
static void
internal_make_private (GelMatrixW *m, int w, int h)
{
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
/* clear caches as we're gonna mess with this matrix */
m->cached_value_only = 0;
m->cached_value_only_real = 0;
m->cached_value_only_rational = 0;
m->cached_value_only_integer = 0;
m->cached_value_or_bool_only = 0;
m->rref = 0;
#ifdef MATRIX_DEBUG
printf ("Make private %p %d %d\n", m, w, h);
#endif
if (m->m->use > 1 ||
has_duplicates (m->regx, m->regw) ||
has_duplicates (m->regy, m->regh)) {
GelMatrix *old = m->m;
#ifdef MATRIX_DEBUG
/*debug*/printf ("HAS_DUPLICATES OR NEEDS COPY\n");
printf ("Has duplicates/copy internal %p %d %d\n", m, w, h);
#endif
/* evil */ old->use ++;
copy_internal_region (m, w, h);
internal_matrix_free (old);
return;
}
}
/*make private copy of the GelMatrix*/
void
gel_matrixw_make_private (GelMatrixW *m)
{
g_return_if_fail(m != NULL);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
internal_make_private (m, m->regw, m->regh);
}
/*free a matrix*/
void
gel_matrixw_free(GelMatrixW *m)
{
GelMatrixWFreeList *mf;
g_return_if_fail(m != NULL);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
internal_matrix_free (m->m);
if (m->regx != NULL)
g_free (m->regx);
if (m->regy != NULL)
g_free (m->regy);
mf = (GelMatrixWFreeList *)m;
#ifdef MEM_DEBUG_FRIENDLY
memset (mf, 0xaa, sizeof (GelMatrixW));
g_free (mf);
#else
mf->next = free_matrices;
free_matrices = mf;
#endif
}
void
gel_matrixw_set_vregion (GelMatrixW *m, GelMatrixW *src, int *desti, int len)
{
int srcelts;
int max;
g_return_if_fail (m != NULL);
g_return_if_fail (src != NULL);
g_return_if_fail (desti != NULL);
g_return_if_fail (len > 0);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
srcelts = src->regw * src->regh;
max = getmax (desti, len);
if (m->tr) {
int i;
if (m->regw == 1) {
internal_make_private (m, m->regw, MAX (max+1, m->regh));
ensure_at_least_size (m, m->regw, max+1);
} else {
int minw = (max / m->regh) + 1;
internal_make_private (m, MAX (minw, m->regw), m->regh);
ensure_at_least_size (m, minw, m->regh);
}
/* assume that's what ensure/make_us_a_copy does */
g_assert (m->regx == NULL && m->regy == NULL);
for (i = 0; i < len; i++) {
int x, y;
GelETree *t;
if (m->regw == 1) {
x = 0;
y = desti[i];
} else {
x = desti[i] / m->regh;
y = desti[i] % m->regh;
}
t = gel_matrix_index (m->m, x, y);
if (i >= srcelts) {
gel_matrix_index (m->m, x, y) = NULL;
} else {
GelETree *s = gel_matrixw_get_vindex (src, i);
if (s != NULL)
s = copynode (s);
gel_matrix_index (m->m, x, y) = s;
}
if (t != NULL)
gel_freetree (t);
}
} else {
int i;
if (m->regh == 1) {
internal_make_private (m, MAX (max+1, m->regw), m->regh);
ensure_at_least_size (m, max+1, m->regh);
} else {
int minh = (max / m->regw) + 1;
internal_make_private (m, m->regw, MAX (minh, m->regh));
ensure_at_least_size (m, m->regw, minh);
}
/* assume that's what ensure/make_us_a_copy does */
g_assert (m->regx == NULL && m->regy == NULL);
for (i = 0; i < len; i++) {
int x, y;
GelETree *t;
if (m->regh == 1) {
x = desti[i];
y = 0;
} else {
x = desti[i] / m->regw;
y = desti[i] % m->regw;
}
t = gel_matrix_index (m->m, x, y);
if (i >= srcelts) {
gel_matrix_index (m->m, x, y) = NULL;
} else {
GelETree *s = gel_matrixw_get_vindex (src, i);
if (s != NULL)
s = copynode (s);
gel_matrix_index (m->m, x, y) = s;
}
if (t != NULL)
gel_freetree (t);
}
}
}
void
gel_matrixw_set_vregion_etree (GelMatrixW *m, GelETree *src, int *desti, int len)
{
g_return_if_fail (m != NULL);
g_return_if_fail (src != NULL);
g_return_if_fail (desti != NULL);
g_return_if_fail (len > 0);
#ifdef MATRIX_DEBUG
/*debug*/printf ("%s\n", G_GNUC_PRETTY_FUNCTION);
#endif
if (m->tr) {
int max = getmax (desti, len);
int minw = (max / m->regh) + 1;
int i;
internal_make_private (m, MAX (minw, m->regw), m->regh);
ensure_at_least_size (m, minw, m->regh);
/* assume that's what ensure/make_us_a_copy does */
g_assert (m->regx == NULL && m->regy == NULL);
for (i = 0; i < len; i++) {
int x = desti[i] / m->regw;
int y = desti[i] % m->regw;
GelETree *t = gel_matrix_index (m->m, x, y);
gel_matrix_index (m->m, x, y) = copynode (src);
if (t != NULL)
gel_freetree (t);
}
} else {
int max = getmax (desti, len);
int minh = (max / m->regw) + 1;
int i;
internal_make_private (m, m->regw, MAX (minh, m->regh));
ensure_at_least_size (m, m->regw, minh);
/* assume that's what ensure/make_us_a_copy does */
g_assert (m->regx == NULL && m->regy == NULL);
for (i = 0; i < len; i++) {
int x = desti[i] % m->regw;
int y = desti[i] / m->regw;
GelETree *t = gel_matrix_index (m->m, x, y);
gel_matrix_index (m->m, x, y) = copynode (src);
if (t != NULL)
gel_freetree (t);
}
}
}
#ifndef G_CAN_INLINE
GelETree *
gel_matrixw_index(GelMatrixW *m, int x, int y) {
GelETree *t = gel_matrixw_get_index (m, x, y);
return t?t:the_zero;
}
#endif
#ifndef G_CAN_INLINE
GelETree *
gel_matrixw_vindex(GelMatrixW *m, int i) {
GelETree *t;
int w = gel_matrixw_width(m);
/* Avoid dividing things */
if (w == 1)
t = gel_matrixw_get_index (m, 0, i);
else if (gel_matrixw_height(m) == 1)
t = gel_matrixw_get_index (m, i, 0);
else
t = gel_matrixw_get_index (m, i % w, i / w);
return t ? t : the_zero;
}
#endif
#ifndef G_CAN_INLINE
G_INLINE_FUNC GelETree *
gel_matrixw_get_vindex(GelMatrixW *m, int i) {
int w = gel_matrixw_width(m);
/* Avoid dividing things */
if (w == 1)
return gel_matrixw_get_index (m, 0, i);
else if (gel_matrixw_height(m) == 1)
return gel_matrixw_get_index (m, i, 0);
else
return gel_matrixw_get_index (m, i % w, i / w);
}
#endif