Files
argyllcms/h/counters.h
2026-08-20 20:28:40 +01:00

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 */