The R Project SVN R

Rev

Rev 88919 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/*
 *  R : A Computer Language for Statistical Data Analysis
 *  Copyright (C) 2001--2024  The R Core Team.
 *
 *  This header file is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2.1 of the License, or
 *  (at your option) any later version.
 *
 *  This file is part of R. R is distributed under the terms of the
 *  GNU General Public License, either Version 2, June 1991 or Version 3,
 *  June 2007. See doc/COPYRIGHTS for details of the copyright status of R.
 *
 *  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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, a copy is available at
 *  https://www.R-project.org/Licenses/
 */

/*
  Macros to help defining vectorized functions with proper recycling
  and periodic interrupt checks.
 */

#ifndef  R_EXT_ITERMACROS_H_
#define  R_EXT_ITERMACROS_H_

#define LOOP_WITH_INTERRUPT_CHECK(LOOP, ncheck, n, ...) do {        \
    for (size_t __intr_threshold__ = ncheck;            \
         TRUE;                          \
         __intr_threshold__ += ncheck) {                \
        size_t __intr_end__ = n < __intr_threshold__ ?      \
        n : __intr_threshold__;                 \
        LOOP(__intr_end__, __VA_ARGS__);                \
        if (__intr_end__ == n) break;               \
        else R_CheckUserInterrupt();                \
    }                               \
    } while (0)

#define R_ITERATE_CORE(n, i, loop_body) do {    \
    for (; i < n; ++i) { loop_body }    \
    } while (0)

#define R_ITERATE(n, i, loop_body) do {     \
    i = 0;                  \
    R_ITERATE_CORE(n, i, loop_body);        \
    } while (0)

#define R_ITERATE_CHECK(ncheck, n, i, loop_body) do {           \
    i = 0;                              \
    LOOP_WITH_INTERRUPT_CHECK(R_ITERATE_CORE, ncheck, n, i, loop_body); \
    } while (0)


#define MOD_ITERATE1_CORE(n, n1, i, i1, loop_body) do { \
    for (; i < n;                           \
         i1 = (++i1 == n1) ? 0 : i1,                \
         ++i) {                         \
        loop_body                           \
        }                           \
    } while (0)

#define MOD_ITERATE1(n, n1, i, i1, loop_body) do {  \
    i = i1 = 0;                 \
    MOD_ITERATE1_CORE(n, n1, i, i1, loop_body); \
    } while (0)

#define MOD_ITERATE1_CHECK(ncheck, n, n1, i, i1, loop_body) do {    \
    i = i1 = 0;                         \
    LOOP_WITH_INTERRUPT_CHECK(MOD_ITERATE1_CORE, ncheck, n,     \
                  n1, i, i1, loop_body);        \
    } while (0)

#define MOD_ITERATE2_CORE(n, n1, n2, i, i1, i2, loop_body) do { \
    for (; i < n;                           \
         i1 = (++i1 == n1) ? 0 : i1,                \
         i2 = (++i2 == n2) ? 0 : i2,                \
         ++i) {                         \
        loop_body                           \
        }                           \
    } while (0)

#define MOD_ITERATE2(n, n1, n2, i, i1, i2, loop_body) do {  \
    i = i1 = i2 = 0;                    \
    MOD_ITERATE2_CORE(n, n1, n2, i, i1, i2, loop_body); \
    } while (0)

#define MOD_ITERATE2_CHECK(ncheck, n, n1, n2, i, i1, i2, loop_body) do {    \
    i = i1 = i2 = 0;                        \
    LOOP_WITH_INTERRUPT_CHECK(MOD_ITERATE2_CORE, ncheck, n,     \
                  n1, n2, i, i1, i2, loop_body);    \
    } while (0)

#define MOD_ITERATE MOD_ITERATE2
#define MOD_ITERATE_CORE MOD_ITERATE2_CORE
#define MOD_ITERATE_CHECK MOD_ITERATE2_CHECK

#define MOD_ITERATE3_CORE(n, n1, n2, n3, i, i1, i2, i3, loop_body) do { \
    for (; i < n;                           \
         i1 = (++i1 == n1) ? 0 : i1,                \
         i2 = (++i2 == n2) ? 0 : i2,                \
         i3 = (++i3 == n3) ? 0 : i3,                \
         ++i) {                         \
        loop_body                           \
        }                           \
    } while (0)

#define MOD_ITERATE3(n, n1, n2, n3, i, i1, i2, i3, loop_body) do {  \
    i = i1 = i2 = i3 = 0;                       \
    MOD_ITERATE3_CORE(n, n1, n2, n3, i, i1, i2, i3, loop_body); \
    } while (0)

#define MOD_ITERATE3_CHECK(ncheck, n, n1, n2, n3, i, i1, i2, i3, loop_body) \
    do {                                \
    i = i1 = i2 = i3 = 0;                       \
    LOOP_WITH_INTERRUPT_CHECK(MOD_ITERATE3_CORE, ncheck, n,     \
                  n1, n2, n3, i, i1, i2, i3, loop_body); \
    } while (0)

#define MOD_ITERATE4_CORE(n, n1, n2, n3, n4, i, i1, i2, i3, i4, loop_body) \
    do {                                \
    for (; i < n;                           \
         i1 = (++i1 == n1) ? 0 : i1,                \
         i2 = (++i2 == n2) ? 0 : i2,                \
         i3 = (++i3 == n3) ? 0 : i3,                \
         i4 = (++i4 == n4) ? 0 : i4,                \
         ++i) {                         \
        loop_body                           \
        }                           \
    } while (0)

#define MOD_ITERATE4(n, n1, n2, n3, n4, i, i1, i2, i3, i4, loop_body) do { \
    i = i1 = i2 = i3 = i4 = 0;                  \
    MOD_ITERATE4_CORE(n, n1, n2, n3, n4, i, i1, i2, i3, i4, loop_body); \
    } while (0)

#define MOD_ITERATE4_CHECK(ncheck, n, n1, n2, n3, n4, i, i1, i2, i3, i4, \
               loop_body)                   \
    do {                                \
    i = i1 = i2 = i3 = i4 = 0;                  \
    LOOP_WITH_INTERRUPT_CHECK(MOD_ITERATE4_CORE, ncheck, n, \
                  n1, n2, n3, n4,           \
                  i, i1, i2, i3, i4, loop_body);    \
    } while (0)

#define MOD_ITERATE5_CORE(n, n1, n2, n3, n4, n5, i, i1, i2, i3, i4, i5, \
              loop_body)                    \
    do {                                \
    for (; i < n;                           \
         i1 = (++i1 == n1) ? 0 : i1,                \
         i2 = (++i2 == n2) ? 0 : i2,                \
         i3 = (++i3 == n3) ? 0 : i3,                \
         i4 = (++i4 == n4) ? 0 : i4,                \
         i5 = (++i5 == n5) ? 0 : i5,                \
         ++i) {                         \
        loop_body                           \
        }                           \
    } while (0)

#define MOD_ITERATE5(n, n1, n2, n3, n4, n5, i, i1, i2, i3, i4, i5, loop_body) \
    do {                                \
    i = i1 = i2 = i3 = i4 = i5 = 0;                 \
    MOD_ITERATE5_CORE(n, n1, n2, n3, n4, n5, i, i1, i2, i3, i4, i5, \
              loop_body);                   \
    } while (0)

#define MOD_ITERATE5_CHECK(ncheck, n, n1, n2, n3, n4, n5, \
               i, i1, i2, i3, i4, i5,           \
               loop_body)                   \
    do {                                \
    i = i1 = i2 = i3 = i4 = i5 = 0;                 \
    LOOP_WITH_INTERRUPT_CHECK(MOD_ITERATE5_CORE, ncheck, n, \
                  n1, n2, n3, n4, n5,           \
                  i, i1, i2, i3, i4, i5, loop_body);    \
    } while (0)

#define GET_REGION_BUFSIZE 512
#ifdef USE_RINTERNALS
# define GET_REGION_PTR(x, i, n, buf, type)             \
    (ALTREP(x) == 0 ? type##0(x) + (i) : (type##_GET_REGION(x, i, n, buf), buf))
#else
# define GET_REGION_PTR(x, i, n, buf, type)             \
    (ALTREP(x) == 0 ? type(x) + (i) : (type##_GET_REGION(x, i, n, buf), buf))
#endif

#define ITERATE_BY_REGION_PARTIAL0(sx, px, idx, nb, etype, vtype,   \
                   strt, nfull, expr) do {      \
    etype __ibr_buf__[GET_REGION_BUFSIZE];              \
    R_xlen_t __ibr_n__ = strt + nfull;              \
    R_xlen_t nb;                            \
    for (R_xlen_t idx = strt; idx < __ibr_n__; idx += nb) {     \
        nb = __ibr_n__  - idx > GET_REGION_BUFSIZE ?        \
        GET_REGION_BUFSIZE :  __ibr_n__ - idx;          \
        etype *px = (etype *) GET_REGION_PTR(sx, idx, nb,       \
                                             __ibr_buf__, vtype);   \
        expr                            \
     }                                  \
    } while (0)

#define ITERATE_BY_REGION_PARTIAL_REV0(sx, px, idx, nb, etype, vtype,   \
                       strt, nfull, expr) do {      \
    etype __ibr_buf__[GET_REGION_BUFSIZE];              \
    R_xlen_t __ibr_n__ = strt + nfull;              \
    R_xlen_t nb = nfull > GET_REGION_BUFSIZE ?          \
        GET_REGION_BUFSIZE : nfull;                 \
    for (R_xlen_t idx = __ibr_n__ - nb; nb > 0; idx -= nb) {    \
        etype *px = (etype *) GET_REGION_PTR(sx, idx, nb,       \
                                             __ibr_buf__, vtype);   \
        expr                            \
        nb = idx - strt > GET_REGION_BUFSIZE ?          \
        GET_REGION_BUFSIZE :  idx - strt;           \
     }                                  \
    } while (0)

#define ITERATE_BY_REGION_PARTIAL(sx, px, idx, nb, etype, vtype,    \
                  strt, nfull, expr) do {       \
    const etype *px = (etype *) DATAPTR_OR_NULL(sx);        \
    if (px != NULL) {                       \
        R_xlen_t idx = strt;                    \
        (void) idx; /* variable may be unused in expr */        \
        R_xlen_t nb = nfull;                    \
        px += strt;                         \
        if (nb > 0) {                                               \
            expr                            \
        }                                                           \
    }                               \
    else ITERATE_BY_REGION_PARTIAL0(sx, px, idx, nb, etype, vtype,  \
                    strt, nfull, expr);     \
    } while (0)

#define ITERATE_BY_REGION_PARTIAL_REV(sx, px, idx, nb, etype, vtype,    \
                      strt, nfull, expr) do {       \
    const etype *px = (etype *) DATAPTR_OR_NULL(sx);        \
    if (px != NULL) {                       \
        R_xlen_t idx = strt;                    \
        (void) idx; /* variable may be unused in expr */        \
        R_xlen_t nb = nfull;                    \
        px += strt;                         \
        if (nb > 0) {                                               \
            expr                            \
        }                                                           \
    }                               \
    else ITERATE_BY_REGION_PARTIAL_REV0(sx, px, idx, nb, etype, \
                        vtype, strt, nfull, expr);  \
    } while (0)

#define ITERATE_BY_REGION(sx, px, idx, nb, etype, vtype, expr) do { \
    ITERATE_BY_REGION_PARTIAL(sx, px, idx, nb, etype, vtype,    \
                  0, XLENGTH(sx), expr);        \
    } while (0)

/* probably no one was using this but it was a declared part of the API
   so leave it in out of an overabundance of caution */

#define ITERATE_BY_REGION0(sx, px, idx, nb, etype, vtype, expr) do {    \
    ITERATE_BY_REGION_PARTIAL0(sx, px, idx, nb, etype, vtype,   \
                  0, XLENGTH(sx), expr);        \
    } while (0)

#endif /* R_EXT_ITERMACROS_H_ */