Coverage Report

Created: 2026-10-16 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/r-source/src/main/relop.c
Line
Count
Source
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1997--2025  The R Core Team
4
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, a copy is available at
18
 *  https://www.R-project.org/Licenses/
19
 */
20
21
22
#ifdef HAVE_CONFIG_H
23
#include <config.h>
24
#endif
25
26
#include <Defn.h>
27
#include <Internal.h>
28
#include <Rmath.h>
29
#include <errno.h>
30
#include <R_ext/Itermacros.h>
31
32
/* interval at which to check interrupts, a guess */
33
#define NINTERRUPT 10000000
34
35
static SEXP numeric_relop(RELOP_TYPE code, SEXP s1, SEXP s2);
36
static SEXP complex_relop(RELOP_TYPE code, SEXP s1, SEXP s2, SEXP call);
37
static SEXP string_relop (RELOP_TYPE code, SEXP s1, SEXP s2);
38
static SEXP raw_relop    (RELOP_TYPE code, SEXP s1, SEXP s2);
39
40
1.70k
#define DO_SCALAR_RELOP(oper, x, y) do {   \
41
1.70k
  switch (oper) {         \
42
468
  case EQOP: return ScalarLogical((x) == (y)); \
43
0
  case NEOP: return ScalarLogical((x) != (y)); \
44
443
  case LTOP: return ScalarLogical((x) < (y)); \
45
477
  case GTOP: return ScalarLogical((x) > (y)); \
46
32
  case LEOP: return ScalarLogical((x) <= (y)); \
47
281
  case GEOP: return ScalarLogical((x) >= (y)); \
48
1.70k
  }           \
49
1.70k
    } while (0)
50
51
attribute_hidden SEXP do_relop(SEXP call, SEXP op, SEXP args, SEXP env)
52
5.09k
{
53
5.09k
    SEXP ans, arg1, arg2;
54
5.09k
    int argc;
55
56
5.09k
    if (args != R_NilValue &&
57
5.09k
  CDR(args) != R_NilValue &&
58
5.09k
  CDDR(args) == R_NilValue)
59
5.09k
  argc = 2;
60
0
    else
61
0
  argc = length(args);
62
5.09k
    arg1 = CAR(args);
63
5.09k
    arg2 = CADR(args);
64
65
5.09k
    if (ATTRIB(arg1) != R_NilValue || ATTRIB(arg2) != R_NilValue) {
66
0
  if (DispatchGroup("Ops", call, op, args, env, &ans))
67
0
      return ans;
68
0
    }
69
70
5.09k
    if (argc != 2)
71
0
  error("operator needs two arguments");
72
73
5.09k
    return do_relop_dflt(call, op, arg1, arg2);
74
5.09k
}
75
76
0
#define IS_SCALAR_STRING(x) (TYPEOF(x) == STRSXP && XLENGTH(x) == 1)
77
#define SYMBOL_STRING_MATCH(x, y) \
78
0
    (isSymbol(x) && IS_SCALAR_STRING(y) && Seql(PRINTNAME(x), STRING_ELT(y, 0)))
79
80
81
static R_INLINE bool compute_lang_equal(SEXP x, SEXP y)
82
0
{
83
0
    if (isSymbol(x))
84
0
  return y == x ||
85
0
      (IS_SCALAR_STRING(y) && Seql(PRINTNAME(x), STRING_ELT(y, 0)));
86
0
    else if (isSymbol(y))
87
0
  return x == y ||
88
0
      (IS_SCALAR_STRING(x) && Seql(STRING_ELT(x, 0), PRINTNAME(y)));
89
90
0
    if (TYPEOF(x) == LANGSXP && ATTRIB(x) != R_NilValue)
91
0
  x = LCONS(CAR(x), CDR(x));
92
0
    PROTECT(x);
93
0
    if (TYPEOF(y) == LANGSXP && ATTRIB(y) != R_NilValue)
94
0
  y = LCONS(CAR(y), CDR(y));
95
0
    PROTECT(y);
96
97
0
    bool val = R_compute_identical(x, y, 16);
98
0
    UNPROTECT(2);
99
0
    return val;
100
0
}
101
102
static SEXP compute_language_relop(SEXP call, SEXP op, SEXP x, SEXP y)
103
0
{
104
0
    static enum {
105
0
  UNINITIALIZED,
106
0
  EQONLY,
107
0
  IDENTICAL_CALLS,
108
0
  IDENTICAL_CALLS_ATTR,
109
0
  IDENTICAL,
110
0
  ERROR_CALLS,
111
0
  ERROR
112
0
    } option = UNINITIALIZED;
113
114
0
    if (option == UNINITIALIZED) {
115
0
  option = EQONLY;
116
0
  const char *val = getenv("_R_COMPARE_LANG_OBJECTS");
117
0
  if (val != NULL) {
118
0
      if (strcmp(val, "eqonly") == 0)
119
0
    option = EQONLY;
120
0
      else if (strcmp(val, "identical_calls") == 0)
121
0
    option = IDENTICAL_CALLS;
122
0
      else if (strcmp(val, "identical_calls_attr") == 0)
123
0
    option = IDENTICAL_CALLS_ATTR;
124
0
      else if (strcmp(val, "identical") == 0)
125
0
    option = IDENTICAL;
126
0
      else if (strcmp(val, "error_calls") == 0)
127
0
    option = ERROR_CALLS;
128
0
      else if (strcmp(val, "error") == 0)
129
0
    option = ERROR;
130
0
  }
131
0
    }
132
133
0
    switch(option) {
134
0
    case EQONLY:
135
0
  switch(PRIMVAL(op)) {
136
0
  case EQOP: return NULL;
137
0
  case NEOP: return NULL;
138
0
  default:
139
0
      errorcall(call,
140
0
          _("comparison (%s) is not possible for language types"),
141
0
          PRIMNAME(op));
142
0
  }
143
0
    case IDENTICAL_CALLS:
144
  /* this should reproduce the current behavior of == and != for
145
     language objects, while signaling errors for <, <=, >, and
146
     >=. */
147
0
  switch(PRIMVAL(op)) {
148
0
  case EQOP:
149
0
      return compute_lang_equal(x, y) ? R_TrueValue : R_FalseValue;
150
0
  case NEOP:
151
0
      return compute_lang_equal(x, y) ? R_FalseValue : R_TrueValue;
152
0
  default:
153
0
      errorcall(call,
154
0
          _("comparison (%s) is not possible for language types"),
155
0
          PRIMNAME(op));
156
0
  }
157
0
    case IDENTICAL_CALLS_ATTR:
158
0
  if (isSymbol(x) && IS_SCALAR_STRING(y))
159
0
      y = Seql(STRING_ELT(y, 0), PRINTNAME(x)) ? x : R_NilValue;
160
0
  else if (isSymbol(y) && IS_SCALAR_STRING(x))
161
0
      x = Seql(STRING_ELT(x, 0), PRINTNAME(y)) ? y : R_NilValue;
162
0
  switch(PRIMVAL(op)) {
163
0
  case EQOP:
164
0
      return R_compute_identical(x, y, 16) ? R_TrueValue : R_FalseValue;
165
0
  case NEOP:
166
0
      return R_compute_identical(x, y, 16) ? R_FalseValue : R_TrueValue;
167
0
  default:
168
0
      errorcall(call,
169
0
          _("comparison (%s) is not possible for language types"),
170
0
          PRIMNAME(op));
171
0
  }
172
0
    case IDENTICAL:
173
0
  if (SYMBOL_STRING_MATCH(x, y) || SYMBOL_STRING_MATCH(y, x))
174
      /* identical(x, y) and the default x == y implementation
175
         would disagree, so signal an error instead */
176
0
      errorcall(call,
177
0
          _("comparing this symbol and string pair "
178
0
      "is not supported"));
179
0
  switch(PRIMVAL(op)) {
180
0
  case EQOP:
181
0
      return R_compute_identical(x, y, 16) ? R_TrueValue : R_FalseValue;
182
0
  case NEOP:
183
0
      return R_compute_identical(x, y, 16) ? R_FalseValue : R_TrueValue;
184
0
  default: errorcall(call,
185
0
         _("comparison (%s) is not possible for language types"),
186
0
         PRIMNAME(op));
187
0
  }
188
0
    case ERROR_CALLS:
189
0
  if (TYPEOF(x) == LANGSXP || TYPEOF(y) == LANGSXP)
190
0
      errorcall(call, _("comparison of call objects is not supported"));
191
0
  return NULL;
192
0
    case ERROR:
193
0
  errorcall(call, _("comparison of language objects is not supported"));
194
0
    default: return NULL;
195
0
    }
196
0
}
197
198
// also called from cmp_relop() in eval.c :
199
attribute_hidden SEXP do_relop_dflt(SEXP call, SEXP op, SEXP x, SEXP y)
200
1.71M
{
201
    /* handle the REALSXP/INTSXP simple scalar case quickly */
202
1.71M
    if (IS_SIMPLE_SCALAR(x, INTSXP)) {
203
980
  int ix = SCALAR_IVAL(x);
204
980
  if (IS_SIMPLE_SCALAR(y, INTSXP)) {
205
916
      int iy = SCALAR_IVAL(y);
206
916
      if (ix == NA_INTEGER || iy == NA_INTEGER)
207
0
    return ScalarLogical(NA_LOGICAL);
208
916
      DO_SCALAR_RELOP(PRIMVAL(op), ix, iy);
209
916
  }
210
64
  else if (IS_SIMPLE_SCALAR(y, REALSXP)) {
211
64
      double dy = SCALAR_DVAL(y);
212
64
      if (ix == NA_INTEGER || ISNAN(dy))
213
0
    return ScalarLogical(NA_LOGICAL);
214
64
      DO_SCALAR_RELOP(PRIMVAL(op), ix, dy);
215
64
  }
216
980
    }
217
1.71M
    else if (IS_SIMPLE_SCALAR(x, REALSXP)) {
218
1.18k
  double dx = SCALAR_DVAL(x);
219
1.18k
  if (IS_SIMPLE_SCALAR(y, INTSXP)) {
220
436
      int iy = SCALAR_IVAL(y);
221
436
      if (ISNAN(dx) || iy == NA_INTEGER)
222
0
    return ScalarLogical(NA_LOGICAL);
223
436
      DO_SCALAR_RELOP(PRIMVAL(op), dx, iy);
224
436
  }
225
744
  else if (IS_SIMPLE_SCALAR(y, REALSXP)) {
226
308
      double dy = SCALAR_DVAL(y);
227
308
      if (ISNAN(dx) || ISNAN(dy))
228
23
    return ScalarLogical(NA_LOGICAL);
229
285
      DO_SCALAR_RELOP(PRIMVAL(op), dx, dy);
230
285
  }
231
1.18k
    }
232
233
1.71M
    R_xlen_t
234
1.71M
  nx = xlength(x),
235
1.71M
  ny = xlength(y);
236
1.71M
    SEXPTYPE
237
1.71M
  typex = TYPEOF(x),
238
1.71M
  typey = TYPEOF(y);
239
240
    /* handle the REALSXP/INTSXP simple vector/scalar case quickly. */
241
1.71M
    if (ATTRIB(x) == R_NilValue && ATTRIB(y) == R_NilValue &&
242
1.70M
  (typex == REALSXP || typex == INTSXP) &&
243
231k
  (typey == REALSXP || typey == INTSXP) &&
244
231k
  nx > 0 && ny > 0 && (nx == 1 || ny == 1)) {
245
246
177k
  PROTECT(x);
247
177k
  PROTECT(y);
248
177k
  SEXP ans;
249
177k
  ans = numeric_relop(PRIMVAL(op), x, y);
250
177k
  UNPROTECT(2);
251
177k
  return ans;
252
177k
    }
253
254
    /* handle the general case */
255
1.53M
    PROTECT_INDEX xpi, ypi;
256
1.53M
    PROTECT_WITH_INDEX(x, &xpi);
257
1.53M
    PROTECT_WITH_INDEX(y, &ypi);
258
259
1.53M
    if (isSymbol(x) || TYPEOF(x) == LANGSXP ||
260
1.53M
  isSymbol(y) || TYPEOF(y) == LANGSXP) {
261
0
  SEXP ans = compute_language_relop(call, op, x, y);
262
0
  if (ans != NULL) {
263
0
      UNPROTECT(2);
264
0
      return ans;
265
0
  }
266
0
    }
267
268
1.53M
    bool iS;
269
    /* That symbols and calls were allowed was undocumented prior to
270
       R 2.5.0.  We deparse them as deparse() would, minus attributes */
271
1.53M
    if ((iS = isSymbol(x)) || TYPEOF(x) == LANGSXP) {
272
0
  SEXP tmp = allocVector(STRSXP, 1);
273
0
  PROTECT(tmp);
274
0
  SET_STRING_ELT(tmp, 0, (iS) ? PRINTNAME(x) :
275
0
           STRING_ELT(deparse1line_ex(x, false,
276
0
              DEFAULTDEPARSE | DIGITS17),
277
0
          0));
278
0
  REPROTECT(x = tmp, xpi);
279
0
  nx = xlength(x);
280
0
  UNPROTECT(1);
281
0
    }
282
1.53M
    if ((iS = isSymbol(y)) || TYPEOF(y) == LANGSXP) {
283
0
  SEXP tmp = allocVector(STRSXP, 1);
284
0
  PROTECT(tmp);
285
0
  SET_STRING_ELT(tmp, 0, (iS) ? PRINTNAME(y) :
286
0
           STRING_ELT(deparse1line_ex(y, false,
287
0
              DEFAULTDEPARSE | DIGITS17),
288
0
          0));
289
0
  REPROTECT(y = tmp, ypi);
290
0
  ny = xlength(y);
291
0
  UNPROTECT(1);
292
0
    }
293
294
1.53M
    if (isNull(x)) REPROTECT(x = allocVector(INTSXP,0), xpi);
295
1.53M
    if (isNull(y)) REPROTECT(y = allocVector(INTSXP,0), ypi);
296
1.53M
    if (!isVector(x) || !isVector(y))
297
0
  errorcall(call,
298
0
      _("comparison (%s) is possible only for atomic and list types"),
299
0
      PRIMNAME(op));
300
301
#ifdef previous_R_versions
302
    if (TYPEOF(x) == EXPRSXP || TYPEOF(y) == EXPRSXP)
303
  errorcall(call, _("comparison is not allowed for expressions"));
304
#endif
305
306
    /* ELSE :  x and y are both atomic or list */
307
308
1.53M
    bool
309
1.53M
  xarray = isArray(x),
310
1.53M
  yarray = isArray(y),
311
1.53M
  xts = isTs(x),
312
1.53M
  yts = isTs(y);
313
1.53M
    SEXP dims, xnames, ynames;
314
1.53M
    if (xarray || yarray) {
315
5.57k
  if (xarray && yarray) {
316
0
      if (!conformable(x, y))
317
0
    errorcall(call, _("non-conformable arrays"));
318
0
      PROTECT(dims = getAttrib(x, R_DimSymbol));
319
0
  }
320
5.57k
  else if (xarray && (ny != 0 || nx == 0)) {
321
5.57k
      PROTECT(dims = getAttrib(x, R_DimSymbol));
322
5.57k
  }
323
0
  else if (yarray && (nx != 0 || ny == 0)) {
324
0
      PROTECT(dims = getAttrib(y, R_DimSymbol));
325
0
  } else
326
0
      PROTECT(dims = R_NilValue);
327
328
5.57k
  PROTECT(xnames = getAttrib(x, R_DimNamesSymbol));
329
5.57k
  PROTECT(ynames = getAttrib(y, R_DimNamesSymbol));
330
5.57k
    }
331
1.53M
    else {
332
1.53M
  PROTECT(dims = R_NilValue);
333
1.53M
  PROTECT(xnames = getAttrib(x, R_NamesSymbol));
334
1.53M
  PROTECT(ynames = getAttrib(y, R_NamesSymbol));
335
1.53M
    }
336
337
1.53M
    SEXP klass = NULL, tsp = NULL; // -Wall
338
1.53M
    if (xts || yts) {
339
0
  if (xts && yts) {
340
      /* could check ts conformance here */
341
0
      PROTECT(tsp = getAttrib(x, R_TspSymbol));
342
0
      PROTECT(klass = getAttrib(x, R_ClassSymbol));
343
0
  }
344
0
  else if (xts) {
345
0
      if (xlength(x) < xlength(y))
346
0
    ErrorMessage(call, ERROR_TSVEC_MISMATCH);
347
0
      PROTECT(tsp = getAttrib(x, R_TspSymbol));
348
0
      PROTECT(klass = getAttrib(x, R_ClassSymbol));
349
0
  }
350
0
  else /*(yts)*/ {
351
0
      if (xlength(y) < xlength(x))
352
0
    ErrorMessage(call, ERROR_TSVEC_MISMATCH);
353
0
      PROTECT(tsp = getAttrib(y, R_TspSymbol));
354
0
      PROTECT(klass = getAttrib(y, R_ClassSymbol));
355
0
  }
356
0
    }
357
358
1.53M
  if (nx > 0 && ny > 0) {
359
1.46M
  if(((nx > ny) ? nx % ny : ny % nx) != 0) // mismatch
360
0
            warningcall(call, _(
361
0
    "longer object length is not a multiple of shorter object length"));
362
363
1.46M
    if (isString(x) || isString(y)) {
364
1.44M
  REPROTECT(x = coerceVector(x, STRSXP), xpi);
365
1.44M
  REPROTECT(y = coerceVector(y, STRSXP), ypi);
366
1.44M
  x = string_relop((RELOP_TYPE) PRIMVAL(op), x, y);
367
1.44M
    }
368
15.4k
    else if (isComplex(x) || isComplex(y)) {
369
0
  REPROTECT(x = coerceVector(x, CPLXSXP), xpi);
370
0
  REPROTECT(y = coerceVector(y, CPLXSXP), ypi);
371
0
  x = complex_relop((RELOP_TYPE) PRIMVAL(op), x, y, call);
372
0
    }
373
15.4k
    else if ((isNumeric(x) || isLogical(x)) && (isNumeric(y) || isLogical(y))) {
374
15.4k
        x = numeric_relop((RELOP_TYPE) PRIMVAL(op), x, y);
375
15.4k
    } // rest of cases only apply when 'x' or 'y' is raw
376
0
    else if (isReal(x) || isReal(y)) {
377
0
  REPROTECT(x = coerceVector(x, REALSXP), xpi);
378
0
  REPROTECT(y = coerceVector(y, REALSXP), ypi);
379
0
  x = numeric_relop((RELOP_TYPE) PRIMVAL(op), x, y);
380
0
    }
381
0
    else if (isInteger(x) || isInteger(y)) {
382
0
  REPROTECT(x = coerceVector(x, INTSXP), xpi);
383
0
  REPROTECT(y = coerceVector(y, INTSXP), ypi);
384
0
  x = numeric_relop((RELOP_TYPE) PRIMVAL(op), x, y);
385
0
    }
386
0
    else if (isLogical(x) || isLogical(y)) {
387
0
  REPROTECT(x = coerceVector(x, LGLSXP), xpi);
388
0
  REPROTECT(y = coerceVector(y, LGLSXP), ypi);
389
0
  x = numeric_relop((RELOP_TYPE) PRIMVAL(op), x, y);
390
0
    }
391
0
    else if (TYPEOF(x) == RAWSXP || TYPEOF(y) == RAWSXP) {
392
0
  REPROTECT(x = coerceVector(x, RAWSXP), xpi);
393
0
  REPROTECT(y = coerceVector(y, RAWSXP), ypi);
394
0
  x = raw_relop((RELOP_TYPE) PRIMVAL(op), x, y);
395
0
    } else errorcall(call, _("comparison of these types is not implemented"));
396
1.46M
  } else { // nx == 0 || ny == 0
397
75.9k
  x = allocVector(LGLSXP, 0);
398
75.9k
  }
399
400
1.53M
    PROTECT(x);
401
1.53M
    if (dims != R_NilValue) {
402
5.57k
  setAttrib(x, R_DimSymbol, dims);
403
5.57k
  if (xnames != R_NilValue)
404
5.57k
      setAttrib(x, R_DimNamesSymbol, xnames);
405
0
  else if (ynames != R_NilValue)
406
0
      setAttrib(x, R_DimNamesSymbol, ynames);
407
5.57k
    }
408
1.53M
    else {
409
1.53M
  if (xnames != R_NilValue && xlength(x) == xlength(xnames))
410
2.98k
      setAttrib(x, R_NamesSymbol, xnames);
411
1.52M
  else if (ynames != R_NilValue && xlength(x) == xlength(ynames))
412
0
      setAttrib(x, R_NamesSymbol, ynames);
413
1.53M
    }
414
1.53M
    if (xts || yts) {
415
0
  setAttrib(x, R_TspSymbol, tsp);
416
0
  setAttrib(x, R_ClassSymbol, klass);
417
0
  UNPROTECT(2);
418
0
    }
419
420
1.53M
    UNPROTECT(6);
421
1.53M
    return x;
422
1.53M
}
423
424
#define ISNA_INT(x) x == NA_INTEGER
425
426
192k
#define NR_HELPER(OP, type1, ACCESSOR1, ISNA1, type2, ACCESSOR2, ISNA2) do { \
427
192k
  type1 x1, *px1 = ACCESSOR1(s1);         \
428
192k
  type2 x2, *px2 = ACCESSOR2(s2);         \
429
192k
  int *pa = LOGICAL(ans);           \
430
192k
        MOD_ITERATE2(n, n1, n2, i, i1, i2, {                            \
431
192k
      x1 = px1[i1];           \
432
192k
      x2 = px2[i2];           \
433
192k
            if (ISNA1(x1) || ISNA2(x2))                                 \
434
192k
                pa[i] = NA_LOGICAL;         \
435
192k
            else                                                        \
436
192k
                pa[i] = (x1 OP x2);         \
437
192k
        });                                                             \
438
192k
    } while (0)
439
440
192k
#define NUMERIC_RELOP(type1, ACCESSOR1, ISNA1, type2, ACCESSOR2, ISNA2) do { \
441
192k
    switch (code) {                                                     \
442
56.0k
    case EQOP:                                                          \
443
56.0k
  NR_HELPER(==, type1, ACCESSOR1, ISNA1, type2, ACCESSOR2, ISNA2); \
444
56.0k
        break;                                                          \
445
4.17k
    case NEOP:                                                          \
446
4.17k
  NR_HELPER(!=, type1, ACCESSOR1, ISNA1, type2, ACCESSOR2, ISNA2); \
447
4.17k
        break;                                                          \
448
2.96k
    case LTOP:                                                          \
449
2.96k
  NR_HELPER(<, type1, ACCESSOR1, ISNA1, type2, ACCESSOR2, ISNA2); \
450
2.96k
        break;                                                          \
451
122k
    case GTOP:                                                          \
452
122k
  NR_HELPER(>, type1, ACCESSOR1, ISNA1, type2, ACCESSOR2, ISNA2); \
453
122k
        break;                                                          \
454
6.81k
    case LEOP:                                                          \
455
6.81k
  NR_HELPER(<=, type1, ACCESSOR1, ISNA1, type2, ACCESSOR2, ISNA2); \
456
6.81k
        break;                                                          \
457
37
    case GEOP:                                                          \
458
37
  NR_HELPER(>=, type1, ACCESSOR1, ISNA1, type2, ACCESSOR2, ISNA2); \
459
37
        break;                                                          \
460
192k
    }                                                                   \
461
192k
} while(0)
462
463
static SEXP numeric_relop(RELOP_TYPE code, SEXP s1, SEXP s2)
464
192k
{
465
192k
    R_xlen_t i, i1, i2, n, n1, n2;
466
192k
    SEXP ans;
467
468
192k
    n1 = XLENGTH(s1);
469
192k
    n2 = XLENGTH(s2);
470
192k
    n = (n1 > n2) ? n1 : n2;
471
192k
    PROTECT(s1);
472
192k
    PROTECT(s2);
473
192k
    ans = allocVector(LGLSXP, n);
474
475
192k
    if (isInteger(s1) || isLogical(s1)) {
476
184k
        if (isInteger(s2) || isLogical(s2)) {
477
179k
            NUMERIC_RELOP(int, INTEGER, ISNA_INT, int, INTEGER, ISNA_INT);
478
179k
        } else {
479
4.28k
            NUMERIC_RELOP(int, INTEGER, ISNA_INT, double, REAL, ISNAN);
480
4.28k
        }
481
184k
    } else if (isInteger(s2) || isLogical(s2)) {
482
3.68k
        NUMERIC_RELOP(double, REAL, ISNAN, int, INTEGER, ISNA_INT);
483
4.72k
    } else {
484
4.72k
        NUMERIC_RELOP(double, REAL, ISNAN, double, REAL, ISNAN);
485
4.72k
    }
486
487
192k
    UNPROTECT(2);
488
192k
    return ans;
489
192k
}
490
491
static SEXP complex_relop(RELOP_TYPE code, SEXP s1, SEXP s2, SEXP call)
492
0
{
493
0
    R_xlen_t i, i1, i2, n, n1, n2;
494
0
    Rcomplex x1, x2;
495
0
    SEXP ans;
496
497
0
    if (code != EQOP && code != NEOP) {
498
0
  errorcall(call, _("invalid comparison with complex values"));
499
0
    }
500
501
0
    n1 = XLENGTH(s1);
502
0
    n2 = XLENGTH(s2);
503
0
    n = (n1 > n2) ? n1 : n2;
504
0
    PROTECT(s1);
505
0
    PROTECT(s2);
506
0
    ans = allocVector(LGLSXP, n);
507
508
0
    const Rcomplex *px1 = COMPLEX_RO(s1);
509
0
    const Rcomplex *px2 = COMPLEX_RO(s2);
510
0
    int *pa = LOGICAL(ans);
511
512
0
    switch (code) {
513
0
    case EQOP:
514
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
515
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
516
0
      x1 = px1[i1];
517
0
      x2 = px2[i2];
518
0
      if (ISNAN(x1.r) || ISNAN(x1.i) ||
519
0
    ISNAN(x2.r) || ISNAN(x2.i))
520
0
    pa[i] = NA_LOGICAL;
521
0
      else
522
0
    pa[i] = (x1.r == x2.r && x1.i == x2.i);
523
0
  });
524
0
  break;
525
0
    case NEOP:
526
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
527
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
528
0
      x1 = px1[i1];
529
0
      x2 = px2[i2];
530
0
      if (ISNAN(x1.r) || ISNAN(x1.i) ||
531
0
    ISNAN(x2.r) || ISNAN(x2.i))
532
0
    pa[i] = NA_LOGICAL;
533
0
      else
534
0
    pa[i] = (x1.r != x2.r || x1.i != x2.i);
535
0
  });
536
0
  break;
537
0
    default:
538
  /* never happens (-Wall) */
539
0
  break;
540
0
    }
541
0
    UNPROTECT(2);
542
0
    return ans;
543
0
}
544
545
546
/* POSIX allows EINVAL when one of the strings contains characters
547
   outside the collation domain. */
548
static SEXP string_relop(RELOP_TYPE code, SEXP s1, SEXP s2)
549
1.44M
{
550
1.44M
    R_xlen_t i, n, n1, n2, res, i1, i2;
551
1.44M
    SEXP ans, c1, c2;
552
1.44M
    const void *vmax = vmaxget(); // for Scollate
553
554
1.44M
    n1 = XLENGTH(s1);
555
1.44M
    n2 = XLENGTH(s2);
556
1.44M
    n = (n1 > n2) ? n1 : n2;
557
1.44M
    PROTECT(s1);
558
1.44M
    PROTECT(s2);
559
1.44M
    PROTECT(ans = allocVector(LGLSXP, n));
560
1.44M
    int *pa = LOGICAL(ans);
561
562
1.44M
    switch (code) {
563
1.25M
    case EQOP:
564
1.25M
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
565
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
566
1.25M
      c1 = STRING_ELT(s1, i1);
567
1.25M
      c2 = STRING_ELT(s2, i2);
568
1.25M
      if (c1 == NA_STRING || c2 == NA_STRING)
569
1.25M
    pa[i] = NA_LOGICAL;
570
1.25M
      else
571
1.25M
    pa[i] = Seql(c1, c2) ? 1 : 0;
572
1.25M
  });
573
1.25M
  break;
574
188k
    case NEOP:
575
188k
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
576
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
577
188k
      c1 = STRING_ELT(s1, i1);
578
188k
      c2 = STRING_ELT(s2, i2);
579
188k
      if (c1 == NA_STRING || c2 == NA_STRING)
580
188k
    pa[i] = NA_LOGICAL;
581
188k
      else
582
188k
    pa[i] = Seql(c1, c2) ? 0 : 1;
583
188k
  });
584
188k
  break;
585
0
    case LTOP:
586
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
587
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
588
0
      c1 = STRING_ELT(s1, i1);
589
0
      c2 = STRING_ELT(s2, i2);
590
0
      if (c1 == NA_STRING || c2 == NA_STRING)
591
0
    pa[i] = NA_LOGICAL;
592
0
      else if (c1 == c2)
593
0
    pa[i] = 0;
594
0
      else {
595
0
    errno = 0;
596
0
    res = Scollate(c1, c2);
597
0
    if(errno)
598
0
        pa[i] = NA_LOGICAL;
599
0
    else
600
0
        pa[i] = (res < 0) ? 1 : 0;
601
0
      }
602
0
  });
603
0
  break;
604
0
    case GTOP:
605
0
  MOD_ITERATE2(n, n1, n2, i ,i1, i2, {
606
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
607
0
      c1 = STRING_ELT(s1, i1);
608
0
      c2 = STRING_ELT(s2, i2);
609
0
      if (c1 == NA_STRING || c2 == NA_STRING)
610
0
    pa[i] = NA_LOGICAL;
611
0
      else if (c1 == c2)
612
0
    pa[i] = 0;
613
0
      else {
614
0
    errno = 0;
615
0
    res = Scollate(c1, c2);
616
0
    if(errno)
617
0
        pa[i] = NA_LOGICAL;
618
0
    else
619
0
        pa[i] = (res > 0) ? 1 : 0;
620
0
      }
621
0
  });
622
0
  break;
623
0
    case LEOP:
624
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
625
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
626
0
      c1 = STRING_ELT(s1, i1);
627
0
      c2 = STRING_ELT(s2, i2);
628
0
      if (c1 == NA_STRING || c2 == NA_STRING)
629
0
    pa[i] = NA_LOGICAL;
630
0
      else if (c1 == c2)
631
0
    pa[i] = 1;
632
0
      else {
633
0
    errno = 0;
634
0
    res = Scollate(c1, c2);
635
0
    if(errno)
636
0
        pa[i] = NA_LOGICAL;
637
0
    else
638
0
        pa[i] = (res <= 0) ? 1 : 0;
639
0
      }
640
0
  });
641
0
  break;
642
0
    case GEOP:
643
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
644
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
645
0
      c1 = STRING_ELT(s1, i1);
646
0
      c2 = STRING_ELT(s2, i2);
647
0
      if (c1 == NA_STRING || c2 == NA_STRING)
648
0
    pa[i] = NA_LOGICAL;
649
0
      else if (c1 == c2)
650
0
    pa[i] = 1;
651
0
      else {
652
0
    errno = 0;
653
0
    res = Scollate(c1, c2);
654
0
    if(errno)
655
0
        pa[i] = NA_LOGICAL;
656
0
    else
657
0
        pa[i] = (res >= 0) ? 1 : 0;
658
0
      }
659
0
  });
660
0
  break;
661
1.44M
    }
662
1.44M
    UNPROTECT(3);
663
1.44M
    vmaxset(vmax);
664
1.44M
    return ans;
665
1.44M
}
666
667
static SEXP raw_relop(RELOP_TYPE code, SEXP s1, SEXP s2)
668
0
{
669
0
    R_xlen_t i, i1, i2, n, n1, n2;
670
0
    Rbyte x1, x2;
671
0
    SEXP ans;
672
673
0
    n1 = XLENGTH(s1);
674
0
    n2 = XLENGTH(s2);
675
0
    n = (n1 > n2) ? n1 : n2;
676
0
    PROTECT(s1);
677
0
    PROTECT(s2);
678
0
    ans = allocVector(LGLSXP, n);
679
680
0
    const Rbyte *px1 = RAW_RO(s1);
681
0
    const Rbyte *px2 = RAW_RO(s2);
682
0
    int *pa = LOGICAL(ans);
683
684
0
    switch (code) {
685
0
    case EQOP:
686
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
687
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
688
0
      x1 = px1[i1];
689
0
      x2 = px2[i2];
690
0
      pa[i] = (x1 == x2);
691
0
  });
692
0
  break;
693
0
    case NEOP:
694
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
695
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
696
0
      x1 = px1[i1];
697
0
      x2 = px2[i2];
698
0
      pa[i] = (x1 != x2);
699
0
  });
700
0
  break;
701
0
    case LTOP:
702
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
703
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
704
0
      x1 = px1[i1];
705
0
      x2 = px2[i2];
706
0
      pa[i] = (x1 < x2);
707
0
  });
708
0
  break;
709
0
    case GTOP:
710
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
711
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
712
0
      x1 = px1[i1];
713
0
      x2 = px2[i2];
714
0
      pa[i] = (x1 > x2);
715
0
  });
716
0
  break;
717
0
    case LEOP:
718
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
719
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
720
0
      x1 = px1[i1];
721
0
      x2 = px2[i2];
722
0
      pa[i] = (x1 <= x2);
723
0
  });
724
0
  break;
725
0
    case GEOP:
726
0
  MOD_ITERATE2(n, n1, n2, i, i1, i2, {
727
//      if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
728
0
      x1 = px1[i1];
729
0
      x2 = px2[i2];
730
0
      pa[i] = (x1 >= x2);
731
0
  });
732
0
  break;
733
0
    }
734
0
    UNPROTECT(2);
735
0
    return ans;
736
0
}
737
738
739
static SEXP bitwiseNot(SEXP a)
740
0
{
741
0
    SEXP ans;
742
0
    int np = 0;
743
0
    if(isReal(a)) {a = PROTECT(coerceVector(a, INTSXP)); np++;}
744
745
0
    switch(TYPEOF(a)) {
746
0
    case INTSXP:
747
0
  {
748
0
      R_xlen_t m = XLENGTH(a);
749
0
      ans = allocVector(INTSXP, m);
750
0
      int *pans = INTEGER(ans);
751
0
      const int *pa = INTEGER_RO(a);
752
0
      for(R_xlen_t i = 0; i < m; i++) {
753
0
    int aa = pa[i];
754
0
    pans[i] = (aa == NA_INTEGER) ? aa : ~aa;
755
0
      }
756
0
  }
757
0
  break;
758
0
    default:
759
0
  UNIMPLEMENTED_TYPE("bitwNot", a);
760
0
    }
761
0
    if(np) UNPROTECT(np);
762
0
    return ans;
763
0
}
764
765
0
#define mymax(x, y) ((x >= y) ? x : y)
766
767
#define BIT(op, name)             \
768
0
    SEXP ans;               \
769
0
    int np = 0;               \
770
0
    if(isReal(a)) {a = PROTECT(coerceVector(a, INTSXP)); np++;}   \
771
0
    if(isReal(b)) {b = PROTECT(coerceVector(b, INTSXP)); np++;}   \
772
0
    if (TYPEOF(a) != TYPEOF(b))           \
773
0
  error(_("'a' and 'b' must have the same type"));   \
774
0
    switch(TYPEOF(a)) {             \
775
0
    case INTSXP:             \
776
0
  {               \
777
0
      R_xlen_t i, ia, ib;           \
778
0
      R_xlen_t m = XLENGTH(a), n = XLENGTH(b),      \
779
0
    mn = (m && n) ? mymax(m, n) : 0;     \
780
0
      ans = allocVector(INTSXP, mn);        \
781
0
      int *pans = INTEGER(ans);         \
782
0
      const int *pa = INTEGER_RO(a), *pb = INTEGER_RO(b);   \
783
0
      MOD_ITERATE2(mn, m, n, i, ia, ib, {       \
784
0
        int aa = pa[ia]; int bb = pb[ib];     \
785
0
        pans[i] = (aa == NA_INTEGER || bb == NA_INTEGER) ?  \
786
0
      NA_INTEGER : aa op bb;        \
787
0
    });             \
788
0
  }               \
789
0
  break;                \
790
0
    default:                \
791
0
  UNIMPLEMENTED_TYPE(name, a);         \
792
0
    }                 \
793
0
    if(np) UNPROTECT(np);           \
794
0
    return ans
795
796
static SEXP bitwiseAnd(SEXP a, SEXP b)
797
0
{
798
0
    BIT(&, "bitwAnd");
799
0
}
800
801
static SEXP bitwiseOr(SEXP a, SEXP b)
802
0
{
803
0
    BIT(|, "bitwOr");
804
0
}
805
806
static SEXP bitwiseXor(SEXP a, SEXP b)
807
0
{
808
0
    BIT(^, "bitwXor");
809
0
}
810
811
static SEXP bitwiseShiftL(SEXP a, SEXP b)
812
0
{
813
0
    SEXP ans;
814
0
    int np = 0;
815
0
    if(isReal(a)) {a = PROTECT(coerceVector(a, INTSXP)); np++;}
816
0
    if(!isInteger(b)) {b = PROTECT(coerceVector(b, INTSXP)); np++;}
817
0
    if (TYPEOF(a) != TYPEOF(b))
818
0
  error(_("'a' and 'b' must have the same type"));
819
820
0
    switch(TYPEOF(a)) {
821
0
    case INTSXP:
822
0
  {
823
0
      R_xlen_t i, ia, ib;
824
0
      R_xlen_t m = XLENGTH(a), n = XLENGTH(b),
825
0
    mn = (m && n) ? mymax(m, n) : 0;
826
0
      ans = allocVector(INTSXP, mn);
827
0
      int *pans = INTEGER(ans);
828
0
      const int *pa = INTEGER_RO(a), *pb = INTEGER_RO(b);
829
0
      MOD_ITERATE2(mn, m, n, i, ia, ib, {
830
0
        int aa = pa[ia]; int bb = pb[ib];
831
0
        pans[i] =
832
0
      (aa == NA_INTEGER || bb == NA_INTEGER ||
833
0
       bb < 0 || bb > 31) ?
834
0
      NA_INTEGER : ((unsigned int)aa << bb);
835
0
    });
836
0
  }
837
0
  break;
838
0
    default:
839
0
  UNIMPLEMENTED_TYPE("bitShiftL", a);
840
0
    }
841
0
    if(np) UNPROTECT(np);
842
0
    return ans;
843
0
}
844
845
static SEXP bitwiseShiftR(SEXP a, SEXP b)
846
0
{
847
0
    SEXP ans;
848
0
    int np = 0;
849
0
    if(isReal(a)) {a = PROTECT(coerceVector(a, INTSXP)); np++;}
850
0
    if(!isInteger(b)) {b = PROTECT(coerceVector(b, INTSXP)); np++;}
851
0
    if (TYPEOF(a) != TYPEOF(b))
852
0
  error(_("'a' and 'b' must have the same type"));
853
854
0
    switch(TYPEOF(a)) {
855
0
    case INTSXP:
856
0
  {
857
0
      R_xlen_t i, ia, ib;
858
0
      R_xlen_t m = XLENGTH(a), n = XLENGTH(b),
859
0
    mn = (m && n) ? mymax(m, n) : 0;
860
0
      ans = allocVector(TYPEOF(a), mn);
861
0
      int *pans = INTEGER(ans);
862
0
      const int *pa = INTEGER_RO(a), *pb = INTEGER_RO(b);
863
0
      MOD_ITERATE2(mn, m, n, i, ia, ib, {
864
0
        int aa = pa[ia]; int bb = pb[ib];
865
0
        pans[i] =
866
0
      (aa == NA_INTEGER || bb == NA_INTEGER ||
867
0
       bb < 0 || bb > 31) ?
868
0
      NA_INTEGER : ((unsigned int)aa >> bb);
869
0
    });
870
0
  }
871
0
  break;
872
0
    default:
873
0
  UNIMPLEMENTED_TYPE("bitShiftR", a);
874
0
    }
875
0
    if(np) UNPROTECT(np);
876
0
    return ans;
877
0
}
878
879
attribute_hidden SEXP do_bitwise(SEXP call, SEXP op, SEXP args, SEXP env)
880
0
{
881
0
    checkArity(op, args);
882
0
    SEXP ans = R_NilValue; /* -Wall */
883
0
    switch(PRIMVAL(op)) {
884
0
    case 1: ans = bitwiseAnd(CAR(args), CADR(args)); break;
885
0
    case 2: ans = bitwiseNot(CAR(args)); break;
886
0
    case 3: ans = bitwiseOr(CAR(args), CADR(args)); break;
887
0
    case 4: ans = bitwiseXor(CAR(args), CADR(args)); break;
888
0
    case 5: ans = bitwiseShiftL(CAR(args), CADR(args)); break;
889
0
    case 6: ans = bitwiseShiftR(CAR(args), CADR(args)); break;
890
0
    }
891
0
    return ans;
892
0
}