/* * 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 #define GET_REGION_PTR(x, i, n, buf, type) \ (ALTREP(x) == 0 ? type##0(x) + (i) : (type##_GET_REGION(x, i, n, buf), buf)) #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_ */