334 lines
9.8 KiB
C
334 lines
9.8 KiB
C
|
|
/*
|
|
* Argyll Color Correction System
|
|
* Multi-dimensional counter macros.
|
|
*
|
|
* Author: Graeme W. Gill
|
|
* Date: 28/9/96
|
|
*
|
|
* Copyright 1996 - 2006, Graeme W. Gill
|
|
* All rights reserved.
|
|
*
|
|
* This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
|
|
* see the License.txt file for licencing details.
|
|
*/
|
|
|
|
#ifndef COUNTERS_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* ------------------------------------------------------- */
|
|
/* Macros for a multi-dimensional counter. */
|
|
/* Declare the counter name nn, maximum di mxdi, dimensions di, & count */
|
|
|
|
#define DCOUNT(nn, mxdi, di, start, reset, endp1) \
|
|
int nn[mxdi]; /* counter value */ \
|
|
int nn##_di = (di); /* Number of dimensions */ \
|
|
int nn##_stt = (start); /* start count value */ \
|
|
int nn##_rst = (reset); /* reset on carry value */ \
|
|
int nn##_res = (endp1); /* last count +1 */ \
|
|
int nn##_e /* dimension index */
|
|
|
|
#define DRECONF(nn, start, reset, endp1) \
|
|
nn##_stt = (start); /* start count value */ \
|
|
nn##_rst = (reset); /* reset on carry value */ \
|
|
nn##_res = (endp1); /* last count +1 */
|
|
|
|
/* Set the counter value to 0 */
|
|
#define DC_INIT(nn) \
|
|
{ \
|
|
for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
|
|
nn[nn##_e] = nn##_stt; \
|
|
nn##_e = 0; \
|
|
}
|
|
|
|
/* Increment the counter value */
|
|
#define DC_INC(nn) \
|
|
{ \
|
|
for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
|
|
nn[nn##_e]++; \
|
|
if (nn[nn##_e] < nn##_res) \
|
|
break; /* No carry */ \
|
|
nn[nn##_e] = nn##_rst; \
|
|
} \
|
|
}
|
|
|
|
/* After init or increment, expression is TRUE if counter is done */
|
|
#define DC_DONE(nn) \
|
|
(nn##_e >= nn##_di)
|
|
|
|
/* Typical use:
|
|
|
|
DCOUNT(cc, 15, 3, -1, -1, 2);
|
|
|
|
DC_INIT(cc);
|
|
while(!DC_DONE(cc)) {
|
|
|
|
DC_INC(cc);
|
|
}
|
|
*/
|
|
|
|
/* (Do we need a version of the above that tracks the actual input coords ?) */
|
|
|
|
/* ------------------------------------------------------- */
|
|
/* Similar to abovem but each dimension range can be clipped. */
|
|
|
|
#define FCOUNT(nn, mxdi, di) \
|
|
int nn[mxdi]; /* counter value */ \
|
|
int nn##_di = (di); /* Dimensions being used */ \
|
|
int nn##_stt[mxdi]; /* start count value */ \
|
|
int nn##_res[mxdi]; /* last count +1 */ \
|
|
int nn##_e /* dimension index */
|
|
|
|
/* Set start and end+1 to uniform values */
|
|
#define FRECONF(nn, start, endp1) \
|
|
for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
|
|
nn##_stt[nn##_e] = (start); /* start count value */ \
|
|
nn##_res[nn##_e] = (endp1); /* last count +1 */ \
|
|
}
|
|
|
|
/* Set start and end+1 to individual values */
|
|
#define FRECONFA(nn, start, endp1) \
|
|
for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
|
|
nn##_stt[nn##_e] = (start)[nn##_e]; /* start count value */ \
|
|
nn##_res[nn##_e] = (endp1)[nn##_e]; /* last count +1 */ \
|
|
}
|
|
|
|
/* Set the dimensions being used */
|
|
#define FSETDI(nn, di) \
|
|
nn##_di = (di); /* Dimensions being used */
|
|
|
|
/* Set a given dimension start and end+1 value */
|
|
#define FSETSTARTEND(nn, ix, start, endp1) \
|
|
nn##_stt[ix] = (start); /* start count value */ \
|
|
nn##_res[ix] = (endp1); /* last count +1 */
|
|
|
|
/* Set the counter value the initial values */
|
|
#define FC_INIT(nn) \
|
|
{ \
|
|
for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
|
|
nn[nn##_e] = nn##_stt[nn##_e]; \
|
|
nn##_e = 0; \
|
|
}
|
|
|
|
/* Increment the counter value */
|
|
#define FC_INC(nn) \
|
|
{ \
|
|
for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
|
|
nn[nn##_e]++; \
|
|
if (nn[nn##_e] < nn##_res[nn##_e]) \
|
|
break; /* No carry */ \
|
|
nn[nn##_e] = nn##_stt[nn##_e]; \
|
|
} \
|
|
}
|
|
|
|
/* After increment, expression is TRUE if counter is done */
|
|
#define FC_DONE(nn) \
|
|
(nn##_e >= nn##_di)
|
|
|
|
/* ------------------------------------------------------- */
|
|
/* Same as above, but allows for variable resolution on each axis. */
|
|
/* End offset is added to count[] */
|
|
/* (Hmm. Could merge FCOUNT and ECOUNT ?) */
|
|
|
|
#define ECOUNT(nn, mxdi, di, start, endp1, end_offst) \
|
|
int nn[mxdi]; /* counter value */ \
|
|
int nn##_di = (di); /* Number of dimensions */ \
|
|
int nn##_start = (start);/* Start value*/ \
|
|
int *nn##_res = (endp1);/* last count +1 */ \
|
|
int nn##_endo = (end_offst);/* Count offset */ \
|
|
int nn##_e /* dimension index */
|
|
|
|
/* Set the counter value to start */
|
|
#define EC_INIT(nn) \
|
|
{ \
|
|
for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
|
|
nn[nn##_e] = nn##_start; \
|
|
nn##_e = 0; \
|
|
}
|
|
|
|
/* Increment the counter value */
|
|
#define EC_INC(nn) \
|
|
{ \
|
|
for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
|
|
nn[nn##_e]++; \
|
|
if (nn[nn##_e] < (nn##_res[nn##_e] + nn##_endo)) \
|
|
break; /* No carry */ \
|
|
nn[nn##_e] = nn##_start; \
|
|
} \
|
|
}
|
|
|
|
/* After increment, expression is TRUE if counter is done */
|
|
#define EC_DONE(nn) \
|
|
(nn##_e >= nn##_di)
|
|
|
|
/* (Do we need a version of the above that tracks the actual input coords ?) */
|
|
|
|
/* ------------------------------------------------------- */
|
|
/* Macros combination counter */
|
|
/* Declare the counter name nn, combinations out of total */
|
|
/* mxdi should be set to maximum combinations. */
|
|
|
|
/* e.g. if there are 8 objects, and we want all combinations */
|
|
/* of 4 out of the 8, we would use: COMBO(nn, 4, 4, 8) */
|
|
|
|
/* Declare and initialize */
|
|
#define COMBO(nn, mxdi, comb, total) \
|
|
int nn[mxdi+2]; /* counter value */ \
|
|
int nn##_cmb = (comb); /* number of combinations */ \
|
|
int nn##_tot = (total); /* out of total possible */ \
|
|
int nn##_e /* dimension index */
|
|
|
|
/* Declare, but don't initialize */
|
|
#define COMBO_DEC(nn, mxdi) \
|
|
int nn[mxdi+2]; /* counter value */ \
|
|
int nn##_cmb; /* number of combinations */ \
|
|
int nn##_tot; /* out of total possible */ \
|
|
int nn##_e /* dimension index */
|
|
|
|
/* Set combinations to new setting */
|
|
#define CB_SETC(nn, comb) \
|
|
nn##_cmb = (comb) /* number of combinations*/
|
|
|
|
/* Set total to new setting */
|
|
#define CB_SETT(nn, total) \
|
|
nn##_tot = (total) /* total possible */
|
|
|
|
/* Set the counter to its initial value */
|
|
#define CB_INIT(nn) \
|
|
{ \
|
|
for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) \
|
|
nn[nn##_e] = nn##_cmb-nn##_e-1; \
|
|
nn##_e = 0; \
|
|
}
|
|
|
|
/* Increment the counter value */
|
|
#define CB_INC(nn) \
|
|
{ \
|
|
for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) { \
|
|
nn[nn##_e]++; \
|
|
if (nn[nn##_e] < (nn##_tot-nn##_e)) { \
|
|
int _combo_ee; /* No carry */ \
|
|
for (_combo_ee = nn##_e-1; _combo_ee >= 0; _combo_ee--) \
|
|
nn[_combo_ee] = nn[_combo_ee+1] + 1; \
|
|
break; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
/* After init or increment, expression is TRUE if counter is done */
|
|
#define CB_DONE(nn) \
|
|
(nn##_e >= nn##_cmb)
|
|
|
|
/* ------------------------------------------------------- */
|
|
/* Macros simplex combination counter. */
|
|
/* Based on COMBO, but skips invalid simplex combinations */
|
|
|
|
#define XCOMBO(nn, mxdi, comb, total) \
|
|
COMBO(nn, mxdi, comb, total)
|
|
|
|
/* Set total to new setting */
|
|
#define XCB_SETT(nn, total) \
|
|
CB_SETT(nn, total)
|
|
|
|
/* Set combinations to new setting */
|
|
#define XCB_SETC(nn, comb) \
|
|
CB_SETC(nn, comb)
|
|
|
|
|
|
/* Set the counter to its initial value */
|
|
#define XCB_INIT(nn) \
|
|
{ \
|
|
int nn##_ii; \
|
|
\
|
|
for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) \
|
|
nn[nn##_e] = nn##_cmb-nn##_e-1; \
|
|
for (nn##_ii = 1; nn##_ii < nn##_cmb; nn##_ii++) { \
|
|
if ((nn[nn##_ii-1] ^ nn[nn##_ii]) & nn[nn##_ii])\
|
|
break; /* Went from 0 to 1 */ \
|
|
} \
|
|
if (nn##_ii < nn##_cmb) { /* Fix invalid combination */ \
|
|
XCB_INC(nn); \
|
|
} \
|
|
nn##_e = 0; \
|
|
}
|
|
|
|
/* Increment the counter value */
|
|
#define XCB_INC(nn) \
|
|
{ \
|
|
int nn##_ii = 0; \
|
|
\
|
|
while (nn##_ii < nn##_cmb) { \
|
|
for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) { \
|
|
nn[nn##_e]++; \
|
|
if (nn[nn##_e] < (nn##_tot-nn##_e)) { \
|
|
int nn##_ee; /* No carry */ \
|
|
for (nn##_ee = nn##_e-1; nn##_ee >= 0; nn##_ee--) \
|
|
nn[nn##_ee] = nn[nn##_ee+1] + 1; \
|
|
break; \
|
|
} \
|
|
} \
|
|
if (nn##_e >= nn##_cmb) \
|
|
break; /* Done */ \
|
|
\
|
|
/* Reject invalid combinations */ \
|
|
for (nn##_ii = 1; nn##_ii < nn##_cmb; nn##_ii++) { \
|
|
if ((nn[nn##_ii-1] ^ nn[nn##_ii]) & nn[nn##_ii]) \
|
|
break; /* Went from 0 to 1 */ \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
/* After init or increment, expression is TRUE if counter is done */
|
|
#define XCB_DONE(nn) \
|
|
CB_DONE(nn)
|
|
|
|
/* ------------------------------------------------------- */
|
|
/* Macros permutation counter */
|
|
/* Declare the counter name nn, number of elements to be permuted */
|
|
/* maxnum should be set to maximum number of elements. */
|
|
|
|
/* Declare and initialize */
|
|
#define PERMUT(nn, maxnum, num) \
|
|
int nn[maxnum]; /* permutation counter */ \
|
|
int nn##p[maxnum]; /* permutation indexes */ \
|
|
int nn##_num = (num); /* number of elements */ \
|
|
int nn##_i /* dimension index */
|
|
|
|
/* Set the counter to its initial value */
|
|
#define PU_INIT(nn) { \
|
|
for (nn##_i = 0; nn##_i < nn##_num; nn##_i++) { \
|
|
nn[nn##_i] = nn##_i; \
|
|
nn##p[nn##_i] = 0; \
|
|
} \
|
|
nn##_i = 0; \
|
|
}
|
|
|
|
/* Increment the counter value */
|
|
#define PU_INC(nn) { \
|
|
int nn##_tt; \
|
|
while (nn##_i < nn##_num && nn##p[nn##_i] >= nn##_i) \
|
|
nn##p[nn##_i++] = 0; \
|
|
if (nn##_i >= nn##_num) \
|
|
break; \
|
|
if (!(nn##_i & 1)) \
|
|
nn##_tt = nn[0], nn[0] = nn[nn##_i], nn[nn##_i] = nn##_tt; \
|
|
else \
|
|
nn##_tt = nn[nn##p[nn##_i]], nn[nn##p[nn##_i]] = nn[nn##_i], nn[nn##_i] = nn##_tt; \
|
|
nn##p[nn##_i]++; \
|
|
nn##_i = 0; \
|
|
}
|
|
|
|
/* After init or increment, expression is TRUE if counter is done */
|
|
#define PU_DONE(nn) \
|
|
(nn##_i >= nn##_num)
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#define COUNTERS_H
|
|
#endif /* COUNTERS_H */
|