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/altclasses.c
Line
Count
Source
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 2016--2026   The R Core Team
4
 *
5
 *  This program is free software; you can redistribute it and/or modify
6
 *  it under the terms of the GNU General Public License as published by
7
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, a copy is available at
17
 *  https://www.R-project.org/Licenses/
18
 */
19
20
#ifdef HAVE_CONFIG_H
21
#include <config.h>
22
#endif
23
24
#include <Defn.h>
25
#include <R_ext/Altrep.h>
26
#include <float.h> /* for DBL_DIG */
27
#include <Print.h> /* for R_print */
28
#include <R_ext/Itermacros.h>
29
30
#ifdef Win32
31
#include <trioremap.h> /* for %lld */
32
#endif
33
34
35
/***
36
 *** ALTREP Concrete Class Implementations
37
 ***/
38
39
/**
40
 ** Compact Integer Sequences
41
 **/
42
43
/*
44
 * Methods
45
 */
46
47
2.08M
#define COMPACT_SEQ_INFO(x) R_altrep_data1(x)
48
1.58M
#define COMPACT_SEQ_EXPANDED(x) R_altrep_data2(x)
49
170k
#define SET_COMPACT_SEQ_EXPANDED(x, v) R_set_altrep_data2(x, v)
50
51
/* needed for now for objects serialized with INTSXP state */
52
#define COMPACT_INTSEQ_SERIALIZED_STATE_LENGTH(info) \
53
123
    (TYPEOF(info) == INTSXP ? INTEGER0(info)[0] : (R_xlen_t) REAL0(info)[0])
54
#define COMPACT_INTSEQ_SERIALIZED_STATE_FIRST(info) \
55
123
    (TYPEOF(info) == INTSXP ? INTEGER0(info)[1] : (int) REAL0(info)[1])
56
#define COMPACT_INTSEQ_SERIALIZED_STATE_INCR(info) \
57
123
    (TYPEOF(info) == INTSXP ? INTEGER0(info)[2] : (int) REAL0(info)[2])
58
59
/* info is stored as REALSXP to allow for long vector length */
60
1.86M
#define COMPACT_INTSEQ_INFO_LENGTH(info) ((R_xlen_t) REAL0(info)[0])
61
393k
#define COMPACT_INTSEQ_INFO_FIRST(info) ((int) REAL0(info)[1])
62
395k
#define COMPACT_INTSEQ_INFO_INCR(info) ((int) REAL0(info)[2])
63
64
/* By default, compact integer sequences are marked as not mutable at
65
   creation time. Thus even when expanded the expanded data will
66
   correspond to the original integer sequence (unless it runs into
67
   mis-behaving C code). If COMPACT_INTSEQ_MUTABLE is defined, then
68
   the sequence is not marked as not mutable. Once the DATAPTR has
69
   been requested and releases, the expanded data might be modified by
70
   an assignment and no longer correspond to the original sequence. */
71
//#define COMPACT_INTSEQ_MUTABLE
72
73
static SEXP compact_intseq_Serialized_state(SEXP x)
74
0
{
75
#ifdef COMPACT_INTSEQ_MUTABLE
76
    /* This drops through to standard serialization for expanded
77
       compact vectors */
78
    if (COMPACT_SEQ_EXPANDED(x) != R_NilValue)
79
  return NULL;
80
#endif
81
0
    return COMPACT_SEQ_INFO(x);
82
0
}
83
84
static SEXP new_compact_intseq(R_xlen_t, int, int);
85
static SEXP new_compact_realseq(R_xlen_t, double, double);
86
87
static SEXP compact_intseq_Unserialize(SEXP class, SEXP state)
88
123
{
89
    /* state is the serialized info vector (see compact_intseq_Serialized_state):
90
       a numeric vector of length 3.  A crafted serialized stream can supply
91
       any object here, so reject a malformed state with a clean error rather
92
       than reading REAL0/INTEGER0 off the end of a short or wrong-typed
93
       (or non-vector) object. */
94
123
    if ((TYPEOF(state) != REALSXP && TYPEOF(state) != INTSXP) ||
95
122
  XLENGTH(state) < 3)
96
4
  error("invalid compact_intseq serialized state");
97
98
123
    R_xlen_t n = COMPACT_INTSEQ_SERIALIZED_STATE_LENGTH(state);
99
123
    int n1 = COMPACT_INTSEQ_SERIALIZED_STATE_FIRST(state);
100
123
    int inc = COMPACT_INTSEQ_SERIALIZED_STATE_INCR(state);
101
102
123
    if (inc == 1)
103
111
  return new_compact_intseq(n, n1,  1);
104
12
    else if (inc == -1)
105
1
  return new_compact_intseq(n, n1,  -1);
106
11
    else
107
11
  error("compact sequences with increment %d not supported yet", inc);
108
123
}
109
 
110
static SEXP compact_intseq_Coerce(SEXP x, int type)
111
2.79k
{
112
#ifdef COMPACT_INTSEQ_MUTABLE
113
    /* This drops through to standard coercion for expanded compact
114
       vectors */
115
    if (COMPACT_SEQ_EXPANDED(x) != R_NilValue)
116
  return NULL;
117
#endif
118
2.79k
    if (type == REALSXP) {
119
0
  SEXP info = COMPACT_SEQ_INFO(x);
120
0
  R_xlen_t n = COMPACT_INTSEQ_INFO_LENGTH(info);
121
0
  int n1 = COMPACT_INTSEQ_INFO_FIRST(info);
122
0
  int inc = COMPACT_INTSEQ_INFO_INCR(info);
123
0
  return new_compact_realseq(n, n1, inc);
124
0
    }
125
2.79k
    else return NULL;
126
2.79k
}
127
128
static SEXP compact_intseq_Duplicate(SEXP x, Rboolean deep)
129
225
{
130
225
    R_xlen_t n = XLENGTH(x);
131
225
    SEXP val = allocVector(INTSXP, n);
132
225
    INTEGER_GET_REGION(x, 0, n, INTEGER0(val));
133
225
    return val;
134
225
}
135
136
static
137
Rboolean compact_intseq_Inspect(SEXP x, int pre, int deep, int pvec,
138
        void (*inspect_subtree)(SEXP, int, int, int))
139
0
{
140
0
    int inc = COMPACT_INTSEQ_INFO_INCR(COMPACT_SEQ_INFO(x));
141
0
    if (inc != 1 && inc != -1)
142
0
  error("compact sequences with increment %d not supported yet", inc);
143
144
#ifdef COMPACT_INTSEQ_MUTABLE
145
    if (COMPACT_SEQ_EXPANDED(x) != R_NilValue) {
146
  Rprintf("  <expanded compact integer sequence>\n");
147
  inspect_subtree(COMPACT_SEQ_EXPANDED(x), pre, deep, pvec);
148
  return TRUE;
149
    }
150
#endif
151
152
0
    R_xlen_t n = XLENGTH(x); // int .. LENGTH(.) not ok, e.g. for -1e9:2e9
153
0
    int n1 = INTEGER_ELT(x, 0);
154
0
    int n2 = (int) ((inc == 1) ? n1 + n - 1 : n1 - n + 1);
155
0
    Rprintf(" %d : %d (%s)", n1, n2,
156
0
      COMPACT_SEQ_EXPANDED(x) == R_NilValue ? "compact" : "expanded");
157
0
    Rprintf("\n");
158
0
    return TRUE;
159
0
}
160
161
static R_INLINE R_xlen_t compact_intseq_Length(SEXP x)
162
1.69M
{
163
1.69M
    SEXP info = COMPACT_SEQ_INFO(x);
164
1.69M
    return COMPACT_INTSEQ_INFO_LENGTH(info);
165
1.69M
}
166
167
static void *compact_intseq_Dataptr(SEXP x, Rboolean writeable)
168
679k
{
169
679k
    if (COMPACT_SEQ_EXPANDED(x) == R_NilValue) {
170
  /* no need to re-run if expanded data exists */
171
170k
  PROTECT(x);
172
170k
  SEXP info = COMPACT_SEQ_INFO(x);
173
170k
  R_xlen_t n = COMPACT_INTSEQ_INFO_LENGTH(info);
174
170k
  int n1 = COMPACT_INTSEQ_INFO_FIRST(info);
175
170k
  int inc = COMPACT_INTSEQ_INFO_INCR(info);
176
170k
  SEXP val = allocVector(INTSXP, n);
177
170k
  int *data = INTEGER(val);
178
179
170k
  if (inc == 1) {
180
      /* compact sequences n1 : n2 with n1 <= n2 */
181
583k
      for (R_xlen_t i = 0; i < n; i++)
182
559k
    data[i] = (int) (n1 + i);
183
23.6k
  }
184
146k
  else if (inc == -1) {
185
      /* compact sequences n1 : n2 with n1 > n2 */
186
4.69M
      for (R_xlen_t i = 0; i < n; i++)
187
4.55M
    data[i] = (int) (n1 - i);
188
146k
  }
189
2
  else
190
2
      error("compact sequences with increment %d not supported yet", inc);
191
192
170k
  SET_COMPACT_SEQ_EXPANDED(x, val);
193
170k
  UNPROTECT(1);
194
170k
    }
195
679k
    return DATAPTR_RW(COMPACT_SEQ_EXPANDED(x));
196
679k
}
197
198
static const void *compact_intseq_Dataptr_or_null(SEXP x)
199
2.29k
{
200
2.29k
    SEXP val = COMPACT_SEQ_EXPANDED(x);
201
2.29k
    return val == R_NilValue ? NULL : DATAPTR_RO(val);
202
2.29k
}
203
204
static int compact_intseq_Elt(SEXP x, R_xlen_t i)
205
223k
{
206
223k
    SEXP ex = COMPACT_SEQ_EXPANDED(x);
207
223k
    if (ex != R_NilValue)
208
1.13k
  return INTEGER0(ex)[i];
209
222k
    else {
210
222k
  SEXP info = COMPACT_SEQ_INFO(x);
211
222k
  int n1 = COMPACT_INTSEQ_INFO_FIRST(info);
212
222k
  int inc = COMPACT_INTSEQ_INFO_INCR(info);
213
222k
  return (int) (n1 + inc * i);
214
222k
    }
215
223k
}
216
217
#define CHECK_NOT_EXPANDED(x)         \
218
841
    if (DATAPTR_OR_NULL(x) != NULL)       \
219
841
  error("method should only handle unexpanded vectors")
220
221
static R_xlen_t
222
compact_intseq_Get_region(SEXP sx, R_xlen_t i, R_xlen_t n, int *buf)
223
841
{
224
    /* should not get here if x is already expanded */
225
841
    CHECK_NOT_EXPANDED(sx);
226
227
841
    SEXP info = COMPACT_SEQ_INFO(sx);
228
841
    R_xlen_t size = COMPACT_INTSEQ_INFO_LENGTH(info);
229
841
    R_xlen_t n1 = COMPACT_INTSEQ_INFO_FIRST(info);
230
841
    int inc = COMPACT_INTSEQ_INFO_INCR(info);
231
232
841
    R_xlen_t ncopy = size - i > n ? n : size - i;
233
841
    if (inc == 1) {
234
45.9k
  for (R_xlen_t k = 0; k < ncopy; k++)
235
45.1k
      buf[k] = (int) (n1 + k + i);
236
841
  return ncopy;
237
841
    }
238
0
    else if (inc == -1) {
239
0
  for (R_xlen_t k = 0; k < ncopy; k++)
240
0
      buf[k] = (int) (n1 - k - i);
241
0
  return ncopy;
242
0
    }
243
0
    else
244
0
  error("compact sequences with increment %d not supported yet", inc);
245
841
}
246
247
static int compact_intseq_Is_sorted(SEXP x)
248
1.84k
{
249
#ifdef COMPACT_INTSEQ_MUTABLE
250
    /* If the vector has been expanded it may have been modified. */
251
    if (COMPACT_SEQ_EXPANDED(x) != R_NilValue)
252
  return UNKNOWN_SORTEDNESS;
253
#endif
254
1.84k
    int inc = COMPACT_INTSEQ_INFO_INCR(COMPACT_SEQ_INFO(x));
255
1.84k
    return inc < 0 ? SORTED_DECR : SORTED_INCR;
256
1.84k
}
257
258
static int compact_intseq_No_NA(SEXP x)
259
616
{
260
#ifdef COMPACT_INTSEQ_MUTABLE
261
    /* If the vector has been expanded it may have been modified. */
262
    if (COMPACT_SEQ_EXPANDED(x) != R_NilValue)
263
  return FALSE;
264
#endif
265
616
    return TRUE;
266
616
}
267
268
/* XXX this also appears in summary.c. move to header file?*/
269
0
#define R_INT_MIN (1 + INT_MIN)
270
271
static SEXP compact_intseq_Sum(SEXP x, Rboolean narm)
272
0
{
273
#ifdef COMPACT_INTSEQ_MUTABLE
274
    /* If the vector has been expanded it may have been modified. */
275
    if (COMPACT_SEQ_EXPANDED(x) != R_NilValue) 
276
  return NULL;
277
#endif
278
0
    double tmp;
279
0
    SEXP info = COMPACT_SEQ_INFO(x);
280
0
    R_xlen_t size = COMPACT_INTSEQ_INFO_LENGTH(info);
281
0
    R_xlen_t n1 = COMPACT_INTSEQ_INFO_FIRST(info);
282
0
    int inc = COMPACT_INTSEQ_INFO_INCR(info);
283
0
    tmp = (size / 2.0) * (n1 + n1 + inc * (size - 1));
284
0
    if(tmp > INT_MAX || tmp < R_INT_MIN)
285
  /**** check for overflow of exact integer range? */
286
0
  return ScalarReal(tmp);
287
0
    else
288
0
  return ScalarInteger((int) tmp);
289
0
}
290
291
292
/*
293
 * Class Objects and Method Tables
294
 */
295
296
R_altrep_class_t R_compact_intseq_class;
297
298
static void InitCompactIntegerClass(void)
299
32
{
300
32
    R_altrep_class_t cls = R_make_altinteger_class("compact_intseq", "base",
301
32
               NULL);
302
32
    R_compact_intseq_class = cls;
303
304
    /* override ALTREP methods */
305
32
    R_set_altrep_Unserialize_method(cls, compact_intseq_Unserialize);
306
32
    R_set_altrep_Serialized_state_method(cls, compact_intseq_Serialized_state);
307
32
    R_set_altrep_Duplicate_method(cls, compact_intseq_Duplicate);
308
32
    R_set_altrep_Coerce_method(cls, compact_intseq_Coerce);
309
32
    R_set_altrep_Inspect_method(cls, compact_intseq_Inspect);
310
32
    R_set_altrep_Length_method(cls, compact_intseq_Length);
311
312
    /* override ALTVEC methods */
313
32
    R_set_altvec_Dataptr_method(cls, compact_intseq_Dataptr);
314
32
    R_set_altvec_Dataptr_or_null_method(cls, compact_intseq_Dataptr_or_null);
315
316
    /* override ALTINTEGER methods */
317
32
    R_set_altinteger_Elt_method(cls, compact_intseq_Elt);
318
32
    R_set_altinteger_Get_region_method(cls, compact_intseq_Get_region);
319
32
    R_set_altinteger_Is_sorted_method(cls, compact_intseq_Is_sorted);
320
32
    R_set_altinteger_No_NA_method(cls, compact_intseq_No_NA);
321
32
    R_set_altinteger_Sum_method(cls, compact_intseq_Sum);
322
32
}
323
324
325
/*
326
 * Constructor
327
 */
328
329
static SEXP new_compact_intseq(R_xlen_t n, int n1, int inc)
330
1.56M
{
331
1.56M
    if (n == 1) return ScalarInteger(n1);
332
333
178k
    if (inc != 1 && inc != -1)
334
0
  error("compact sequences with increment %d not supported yet", inc);
335
336
    /* info used REALSXP to allow for long vectors */
337
178k
    SEXP info = allocVector(REALSXP, 3);
338
178k
    REAL0(info)[0] = (double) n;
339
178k
    REAL0(info)[1] = (double) n1;
340
178k
    REAL0(info)[2] = (double) inc;
341
342
178k
    SEXP ans = R_new_altrep(R_compact_intseq_class, info, R_NilValue);
343
178k
#ifndef COMPACT_INTSEQ_MUTABLE
344
178k
    MARK_NOT_MUTABLE(ans); /* force duplicate on modify */
345
178k
#endif
346
347
178k
    return ans;
348
1.56M
}
349
350
attribute_hidden Rboolean R_is_compact_intseq(SEXP x)
351
565
{
352
565
    return R_altrep_inherits(x, R_compact_intseq_class);
353
565
}
354
355
356
/**
357
 ** Compact Real Sequences
358
 **/
359
360
/*
361
 * Methods
362
 */
363
364
0
#define COMPACT_REALSEQ_INFO_LENGTH(info) ((R_xlen_t) REAL0(info)[0])
365
0
#define COMPACT_REALSEQ_INFO_FIRST(info) REAL0(info)[1]
366
0
#define COMPACT_REALSEQ_INFO_INCR(info) REAL0(info)[2]
367
368
static SEXP compact_realseq_Serialized_state(SEXP x)
369
0
{
370
0
    return COMPACT_SEQ_INFO(x);
371
0
}
372
373
static SEXP compact_realseq_Unserialize(SEXP class, SEXP state)
374
0
{
375
    /* as for compact_intseq_Unserialize: the info vector read below is a
376
       length-3 REALSXP, but a crafted stream can supply anything, so reject
377
       a malformed state rather than reading REAL0 off the end. */
378
0
    if (TYPEOF(state) != REALSXP || XLENGTH(state) < 3)
379
0
  error("invalid compact_realseq serialized state");
380
381
0
    double inc = COMPACT_REALSEQ_INFO_INCR(state);
382
0
    R_xlen_t len = COMPACT_REALSEQ_INFO_LENGTH(state);
383
0
    double n1 = COMPACT_REALSEQ_INFO_FIRST(state);
384
385
0
    if (inc == 1)
386
0
  return new_compact_realseq(len, n1,  1);
387
0
    else if (inc == -1)
388
0
  return new_compact_realseq(len, n1, -1);
389
0
    else
390
0
  error("compact sequences with increment %f not supported yet", inc);
391
0
}
392
393
static SEXP compact_realseq_Duplicate(SEXP x, Rboolean deep)
394
0
{
395
0
    R_xlen_t n = XLENGTH(x);
396
0
    SEXP val = allocVector(REALSXP, n);
397
0
    REAL_GET_REGION(x, 0, n, REAL0(val));
398
0
    return val;
399
0
}
400
401
static
402
Rboolean compact_realseq_Inspect(SEXP x, int pre, int deep, int pvec,
403
         void (*inspect_subtree)(SEXP, int, int, int))
404
0
{
405
0
    double inc = COMPACT_REALSEQ_INFO_INCR(COMPACT_SEQ_INFO(x));
406
0
    if (inc != 1 && inc != -1)
407
0
  error("compact sequences with increment %f not supported yet", inc);
408
409
0
    R_xlen_t n = XLENGTH(x);
410
0
    R_xlen_t n1 = (R_xlen_t) REAL_ELT(x, 0);
411
0
    R_xlen_t n2 = inc == 1 ? n1 + n - 1 : n1 - n + 1;
412
0
    Rprintf(" %lld : %lld (%s)", (long long)n1, (long long)n2,
413
0
      COMPACT_SEQ_EXPANDED(x) == R_NilValue ? "compact" : "expanded");
414
0
    Rprintf("\n");
415
0
    return TRUE;
416
0
}
417
418
static R_INLINE R_xlen_t compact_realseq_Length(SEXP x)
419
0
{
420
0
    return (R_xlen_t) REAL0(COMPACT_SEQ_INFO(x))[0];
421
0
}
422
423
static void *compact_realseq_Dataptr(SEXP x, Rboolean writeable)
424
0
{
425
0
    if (COMPACT_SEQ_EXPANDED(x) == R_NilValue) {
426
0
  PROTECT(x);
427
0
  SEXP info = COMPACT_SEQ_INFO(x);
428
0
  R_xlen_t n = COMPACT_REALSEQ_INFO_LENGTH(info);
429
0
  double n1 = COMPACT_REALSEQ_INFO_FIRST(info);
430
0
  double inc = COMPACT_REALSEQ_INFO_INCR(info);
431
  
432
0
  SEXP val = allocVector(REALSXP, (R_xlen_t) n);
433
0
  double *data = REAL(val);
434
435
0
  if (inc == 1) {
436
      /* compact sequences n1 : n2 with n1 <= n2 */
437
0
      for (R_xlen_t i = 0; i < n; i++)
438
0
    data[i] = n1 + i;
439
0
  }
440
0
  else if (inc == -1) {
441
      /* compact sequences n1 : n2 with n1 > n2 */
442
0
      for (R_xlen_t i = 0; i < n; i++)
443
0
    data[i] = n1 - i;
444
0
  }
445
0
  else
446
0
      error("compact sequences with increment %f not supported yet", inc);
447
448
0
  SET_COMPACT_SEQ_EXPANDED(x, val);
449
0
  UNPROTECT(1);
450
0
    }
451
0
    return DATAPTR_RW(COMPACT_SEQ_EXPANDED(x));
452
0
}
453
454
static const void *compact_realseq_Dataptr_or_null(SEXP x)
455
0
{
456
0
    SEXP val = COMPACT_SEQ_EXPANDED(x);
457
0
    return val == R_NilValue ? NULL : DATAPTR_RO(val);
458
0
}
459
460
static double compact_realseq_Elt(SEXP x, R_xlen_t i)
461
0
{
462
0
    SEXP ex = COMPACT_SEQ_EXPANDED(x);
463
0
    if (ex != R_NilValue)
464
0
  return REAL0(ex)[i];
465
0
    else {
466
0
  SEXP info = COMPACT_SEQ_INFO(x);
467
0
  double n1 = COMPACT_REALSEQ_INFO_FIRST(info);
468
0
  double inc = COMPACT_REALSEQ_INFO_INCR(info);
469
0
  return n1 + inc * i;
470
0
    }
471
0
}
472
473
static R_xlen_t
474
compact_realseq_Get_region(SEXP sx, R_xlen_t i, R_xlen_t n, double *buf)
475
0
{
476
    /* should not get here if x is already expanded */
477
0
    CHECK_NOT_EXPANDED(sx);
478
479
0
    SEXP info = COMPACT_SEQ_INFO(sx);
480
0
    R_xlen_t size = COMPACT_REALSEQ_INFO_LENGTH(info);
481
0
    double n1 = COMPACT_REALSEQ_INFO_FIRST(info);
482
0
    double inc = COMPACT_REALSEQ_INFO_INCR(info);
483
484
0
    R_xlen_t ncopy = size - i > n ? n : size - i;
485
0
    if (inc == 1) {
486
0
  for (R_xlen_t k = 0; k < ncopy; k++)
487
0
      buf[k] = n1 + k + i;
488
0
  return ncopy;
489
0
    }
490
0
    else if (inc == -1) {
491
0
  for (R_xlen_t k = 0; k < ncopy; k++)
492
0
      buf[k] = n1 - k - i;
493
0
  return ncopy;
494
0
    }
495
0
    else
496
0
  error("compact sequences with increment %f not supported yet", inc);
497
0
}
498
    
499
static int compact_realseq_Is_sorted(SEXP x)
500
0
{
501
#ifdef COMPACT_REALSEQ_MUTABLE
502
    /* If the vector has been expanded it may have been modified. */
503
    if (COMPACT_SEQ_EXPANDED(x) != R_NilValue)
504
  return UNKNOWN_SORTEDNESS;
505
#endif
506
0
    double inc = COMPACT_REALSEQ_INFO_INCR(COMPACT_SEQ_INFO(x));
507
0
    return inc < 0 ? SORTED_DECR : SORTED_INCR;
508
0
}
509
510
static int compact_realseq_No_NA(SEXP x)
511
0
{
512
#ifdef COMPACT_REALSEQ_MUTABLE
513
    /* If the vector has been expanded it may have been modified. */
514
    if (COMPACT_SEQ_EXPANDED(x) != R_NilValue)
515
  return FALSE;
516
#endif
517
0
    return TRUE;
518
0
}
519
520
static SEXP compact_realseq_Sum(SEXP x, Rboolean narm)
521
0
{
522
#ifdef COMPACT_INTSEQ_MUTABLE
523
    /* If the vector has been expanded it may have been modified. */
524
    if (COMPACT_SEQ_EXPANDED(x) != R_NilValue) 
525
  return NULL;
526
#endif
527
0
    SEXP info = COMPACT_SEQ_INFO(x);
528
0
    double size = (double) COMPACT_REALSEQ_INFO_LENGTH(info);
529
0
    double n1 = COMPACT_REALSEQ_INFO_FIRST(info);
530
0
    double inc = COMPACT_REALSEQ_INFO_INCR(info);
531
0
    return ScalarReal((size / 2.0) *(n1 + n1 + inc * (size - 1)));
532
0
}
533
534
535
/*
536
 * Class Objects and Method Tables
537
 */
538
539
540
R_altrep_class_t R_compact_realseq_class;
541
542
static void InitCompactRealClass(void)
543
32
{
544
32
    R_altrep_class_t cls = R_make_altreal_class("compact_realseq", "base",
545
32
            NULL);
546
32
    R_compact_realseq_class = cls;
547
548
    /* override ALTREP methods */
549
32
    R_set_altrep_Unserialize_method(cls, compact_realseq_Unserialize);
550
32
    R_set_altrep_Serialized_state_method(cls, compact_realseq_Serialized_state);
551
32
    R_set_altrep_Duplicate_method(cls, compact_realseq_Duplicate);
552
32
    R_set_altrep_Inspect_method(cls, compact_realseq_Inspect);
553
32
    R_set_altrep_Length_method(cls, compact_realseq_Length);
554
555
    /* override ALTVEC methods */
556
32
    R_set_altvec_Dataptr_method(cls, compact_realseq_Dataptr);
557
32
    R_set_altvec_Dataptr_or_null_method(cls, compact_realseq_Dataptr_or_null);
558
559
    /* override ALTREAL methods */
560
32
    R_set_altreal_Elt_method(cls, compact_realseq_Elt);
561
32
    R_set_altreal_Get_region_method(cls, compact_realseq_Get_region);
562
32
    R_set_altreal_Is_sorted_method(cls, compact_realseq_Is_sorted);
563
32
    R_set_altreal_No_NA_method(cls, compact_realseq_No_NA);
564
32
    R_set_altreal_Sum_method(cls, compact_realseq_Sum);
565
32
}
566
567
568
/*
569
 * Constructor
570
 */
571
572
static SEXP new_compact_realseq(R_xlen_t n, double n1, double inc)
573
0
{
574
0
    if (n == 1) return ScalarReal(n1);
575
576
0
    if (inc != 1 && inc != -1)
577
0
  error("compact sequences with increment %f not supported yet", inc);
578
579
0
    SEXP info = allocVector(REALSXP, 3);
580
0
    REAL(info)[0] = n;
581
0
    REAL(info)[1] = n1;
582
0
    REAL(info)[2] = inc;
583
584
0
    SEXP ans = R_new_altrep(R_compact_realseq_class, info, R_NilValue);
585
0
    MARK_NOT_MUTABLE(ans); /* force duplicate on modify */
586
587
0
    return ans;
588
0
}
589
590
591
/**
592
 ** Compact Integer/Real Sequences
593
 **/
594
595
attribute_hidden SEXP R_compact_intrange(R_xlen_t n1, R_xlen_t n2)
596
1.56M
{
597
1.56M
    R_xlen_t n = n1 <= n2 ? n2 - n1 + 1 : n1 - n2 + 1;
598
599
1.56M
    if (n >= R_XLEN_T_MAX)
600
0
  error("result would be too long a vector");
601
602
1.56M
    if (n1 <= INT_MIN || n1 > INT_MAX || n2 <= INT_MIN || n2 > INT_MAX)
603
0
  return new_compact_realseq(n, n1, n1 <= n2 ? 1 : -1);
604
1.56M
    else
605
1.56M
  return new_compact_intseq(n, (int) n1, n1 <= n2 ? 1 : -1);
606
1.56M
}
607
608
609
/**
610
 ** Deferred String Coercions
611
 **/
612
613
/*
614
 * Methods
615
 */
616
617
6.60M
#define DEFERRED_STRING_STATE(x) R_altrep_data1(x)
618
1.63k
#define CLEAR_DEFERRED_STRING_STATE(x) R_set_altrep_data1(x, R_NilValue)
619
2.54M
#define DEFERRED_STRING_EXPANDED(x) R_altrep_data2(x)
620
259k
#define SET_DEFERRED_STRING_EXPANDED(x, v) R_set_altrep_data2(x, v)
621
622
#define MAKE_DEFERRED_STRING_STATE(v, sp) CONS(v, sp)
623
4.72M
#define DEFERRED_STRING_STATE_ARG(s) CAR(s)
624
53.8k
#define DEFERRED_STRING_STATE_INFO(s) CDR(s)
625
626
#define DEFERRED_STRING_ARG(x) \
627
619k
    DEFERRED_STRING_STATE_ARG(DEFERRED_STRING_STATE(x))
628
#define DEFERRED_STRING_INFO(x) \
629
26.9k
    DEFERRED_STRING_STATE_INFO(DEFERRED_STRING_STATE(x))
630
#define DEFERRED_STRING_SCIPEN(x) \
631
26.9k
    INTEGER0(DEFERRED_STRING_STATE_INFO(DEFERRED_STRING_STATE(x)))[0]
632
633
/* work-around for package code that mutates things it shouldn't and
634
   makes serialize and inspect infinite-loop */
635
0
#define DEFERRED_STRING_FIXUP_ARG_ATTRIBS(state) do {     \
636
0
  if (state != R_NilValue && ATTRIB(CAR(state)) != R_NilValue) { \
637
0
      SETCAR(state, shallow_duplicate(CAR(state)));    \
638
0
      SET_ATTRIB(CAR(state), R_NilValue);       \
639
0
  }               \
640
0
    } while (0)
641
    
642
static SEXP R_OutDecSym = NULL;
643
644
static R_INLINE const char *DEFERRED_STRING_OUTDEC(SEXP x)
645
26.9k
{
646
    /* The default value of OutDec at startup is ".". If it is
647
       something different at the time the deferred string conversion
648
       is created then the current value is stored as an attribute. */
649
26.9k
    if (R_OutDecSym == NULL)
650
32
  R_OutDecSym = install("OutDec");
651
26.9k
    SEXP info = DEFERRED_STRING_INFO(x);
652
26.9k
    if (ATTRIB(info) != R_NilValue) {
653
2.62k
  SEXP outdecattr = getAttrib(info, R_OutDecSym);
654
2.62k
  if (TYPEOF(outdecattr) == STRSXP && XLENGTH(outdecattr) == 1)
655
2.62k
      return CHAR(STRING_ELT(outdecattr, 0));
656
2.62k
    }
657
24.3k
    return ".";
658
26.9k
}
659
660
static SEXP deferred_string_Serialized_state(SEXP x)
661
0
{
662
    /* This drops through to standard serialization for fully expanded
663
       deferred string conversions. Partial expansions are OK since
664
       they still correspond to the original data. An assignment to
665
       the object will access the DATAPTR and force a full expansion
666
       and dropping the original data. */
667
0
    SEXP state = DEFERRED_STRING_STATE(x);
668
0
    DEFERRED_STRING_FIXUP_ARG_ATTRIBS(state);
669
0
    return state != R_NilValue ? state : NULL;
670
0
}
671
672
static SEXP deferred_string_Unserialize(SEXP class, SEXP state)
673
0
{
674
0
    SEXP arg = DEFERRED_STRING_STATE_ARG(state);
675
0
    SEXP info = DEFERRED_STRING_STATE_INFO(state);
676
0
    return R_deferred_coerceToString(arg, info);
677
0
}
678
679
static
680
Rboolean deferred_string_Inspect(SEXP x, int pre, int deep, int pvec,
681
         void (*inspect_subtree)(SEXP, int, int, int))
682
0
{
683
0
    SEXP state = DEFERRED_STRING_STATE(x);
684
0
    if (state != R_NilValue) {
685
0
  DEFERRED_STRING_FIXUP_ARG_ATTRIBS(state);
686
0
  SEXP arg = DEFERRED_STRING_STATE_ARG(state);
687
0
  Rprintf("  <deferred string conversion>\n");
688
0
  inspect_subtree(arg, pre, deep, pvec);
689
0
    }
690
0
    else {
691
0
  Rprintf("  <expanded string conversion>\n");
692
0
  inspect_subtree(DEFERRED_STRING_EXPANDED(x), pre, deep, pvec);
693
0
    }
694
0
    return TRUE;
695
0
}
696
697
static R_INLINE R_xlen_t deferred_string_Length(SEXP x)
698
4.18M
{
699
4.18M
    SEXP state = DEFERRED_STRING_STATE(x);
700
4.18M
    return state == R_NilValue ?
701
83.0k
  XLENGTH(DEFERRED_STRING_EXPANDED(x)) :
702
4.18M
  XLENGTH(DEFERRED_STRING_STATE_ARG(state));
703
4.18M
}
704
705
static R_INLINE SEXP ExpandDeferredStringElt(SEXP x, R_xlen_t i)
706
2.37M
{
707
    /* make sure the STRSXP for the expanded string is allocated */
708
    /* not yet expanded strings are NULL in the STRSXP */
709
2.37M
    SEXP val = DEFERRED_STRING_EXPANDED(x);
710
2.37M
    if (val == R_NilValue) {
711
259k
  R_xlen_t n = XLENGTH(x);
712
259k
  val = allocVector(STRSXP, n);
713
259k
  if (n)
714
259k
      memset(STDVEC_DATAPTR(val), 0, n * sizeof(SEXP));
715
259k
  SET_DEFERRED_STRING_EXPANDED(x, val);
716
259k
    }
717
718
2.37M
    SEXP elt = STRING_ELT(val, i);
719
2.37M
    if (elt == NULL) {
720
619k
  int warn; /* not used by the coercion functions */
721
619k
  int savedigits, savescipen;
722
619k
  SEXP data = DEFERRED_STRING_ARG(x);
723
619k
  switch(TYPEOF(data)) {
724
592k
  case INTSXP:
725
592k
      elt = StringFromInteger(INTEGER_ELT(data, i), &warn);
726
592k
      break;
727
26.9k
  case REALSXP:
728
26.9k
      savedigits = R_print.digits;
729
26.9k
      savescipen = R_print.scipen;
730
26.9k
      R_print.digits = DBL_DIG;/* MAX precision */
731
26.9k
      R_print.scipen = DEFERRED_STRING_SCIPEN(x);
732
26.9k
      const char *myoutdec = DEFERRED_STRING_OUTDEC(x);
733
26.9k
      if (strcmp(OutDec, myoutdec)) {
734
    /* The current and saved OutDec values differ. The
735
       value to use is put in a static buffer and OutDec
736
       temporarily points to this buffer while
737
       StringFromReal is called and then reset. The buffer
738
       originally pointed to by OutDec cannot be used as
739
       it wil not be writable if the default "." has not
740
       been changed. */
741
0
    static char buf[10];
742
0
    strncpy(buf, myoutdec, sizeof buf);
743
0
    buf[sizeof(buf) - 1] = '\0';
744
0
    char *savedOutDec = OutDec;
745
0
    OutDec = buf;
746
0
    elt = StringFromReal(REAL_ELT(data, i), &warn);
747
0
    OutDec = savedOutDec;
748
0
      }
749
26.9k
      else
750
26.9k
    elt = StringFromReal(REAL_ELT(data, i), &warn);
751
26.9k
      R_print.digits = savedigits;
752
26.9k
      R_print.scipen = savescipen;
753
26.9k
      break;
754
0
  default:
755
0
      error("unsupported type for deferred string coercion");
756
619k
  }
757
619k
  SET_STRING_ELT(val, i, elt);
758
619k
    }
759
2.37M
    return elt;
760
2.37M
}
761
762
static R_INLINE void expand_deferred_string(SEXP x)
763
19.8k
{
764
19.8k
    SEXP state = DEFERRED_STRING_STATE(x);
765
19.8k
    if (state != R_NilValue) {
766
  /* expanded data may be incomplete until original data is removed */
767
1.63k
  PROTECT(x);
768
1.63k
  R_xlen_t n = XLENGTH(x), i;
769
1.63k
  if (n == 0)
770
0
      SET_DEFERRED_STRING_EXPANDED(x, allocVector(STRSXP, 0));
771
1.63k
  else
772
43.8k
      for (i = 0; i < n; i++)
773
42.2k
    ExpandDeferredStringElt(x, i);
774
1.63k
  CLEAR_DEFERRED_STRING_STATE(x); /* allow arg to be reclaimed */
775
1.63k
  UNPROTECT(1);
776
1.63k
    }
777
19.8k
}
778
779
static void *deferred_string_Dataptr(SEXP x, Rboolean writeable)
780
436
{
781
436
    expand_deferred_string(x);
782
436
    return DATAPTR_RW(DEFERRED_STRING_EXPANDED(x));
783
436
}
784
785
static const void *deferred_string_Dataptr_or_null(SEXP x)
786
0
{
787
0
    SEXP state = DEFERRED_STRING_STATE(x);
788
0
    return state != R_NilValue ? NULL : DATAPTR_RO(DEFERRED_STRING_EXPANDED(x));
789
0
}
790
791
static SEXP deferred_string_Elt(SEXP x, R_xlen_t i)
792
2.39M
{
793
2.39M
    SEXP state = DEFERRED_STRING_STATE(x);
794
2.39M
    if (state == R_NilValue)
795
  /* string is fully expanded */
796
62.4k
  return STRING_ELT(DEFERRED_STRING_EXPANDED(x), i);
797
2.33M
    else {
798
  /* expand only the requested element */
799
2.33M
  PROTECT(x);
800
2.33M
  SEXP elt = ExpandDeferredStringElt(x, i);
801
2.33M
  UNPROTECT(1);
802
2.33M
  return elt;
803
2.33M
    }
804
2.39M
}
805
806
static void deferred_string_Set_elt(SEXP x, R_xlen_t i, SEXP v)
807
19.3k
{
808
19.3k
    expand_deferred_string(x);
809
19.3k
    SET_STRING_ELT(DEFERRED_STRING_EXPANDED(x), i, v);
810
19.3k
}
811
812
static int deferred_string_Is_sorted(SEXP x)
813
0
{
814
    /* same as the default method; sortedness of the numeric is not relevant  */
815
0
    return UNKNOWN_SORTEDNESS;
816
0
}
817
818
static int deferred_string_No_NA(SEXP x)
819
0
{
820
0
    SEXP state = DEFERRED_STRING_STATE(x);
821
0
    if (state == R_NilValue)
822
  /* string is fully expanded and may have been modified. */
823
0
  return FALSE;
824
0
    else {
825
  /* defer to the argument */
826
0
  SEXP arg = DEFERRED_STRING_STATE_ARG(state);
827
0
  switch(TYPEOF(arg)) {
828
0
  case INTSXP: return INTEGER_NO_NA(arg);
829
0
  case REALSXP: return REAL_NO_NA(arg);
830
0
  default: return FALSE;
831
0
  }
832
0
    }
833
0
}
834
835
static SEXP deferred_string_Extract_subset(SEXP x, SEXP indx, SEXP call)
836
0
{
837
0
    SEXP result = NULL;
838
839
0
    if (! OBJECT(x) && ATTRIB(x) == R_NilValue &&
840
0
  DEFERRED_STRING_STATE(x) != R_NilValue) {
841
  /* For deferred string coercions, create a new conversion
842
     using the subset of the argument.  Could try to
843
     preserve/share coercions already done, if there are any. */
844
0
  SEXP data = DEFERRED_STRING_ARG(x);
845
0
  SEXP info = DEFERRED_STRING_INFO(x);
846
0
  PROTECT(result = ExtractSubset(data, indx, call));
847
0
  result = R_deferred_coerceToString(result, info);
848
0
  UNPROTECT(1);
849
0
  return result;
850
0
    }
851
852
0
    return result;
853
0
}
854
855
856
/*
857
 * Class Object and Method Table
858
 */
859
860
static R_altrep_class_t R_deferred_string_class;
861
862
static void InitDefferredStringClass(void)
863
32
{
864
32
    R_altrep_class_t cls = R_make_altstring_class("deferred_string", "base",
865
32
              NULL);
866
32
    R_deferred_string_class = cls;
867
868
    /* override ALTREP methods */
869
32
    R_set_altrep_Unserialize_method(cls, deferred_string_Unserialize);
870
32
    R_set_altrep_Serialized_state_method(cls, deferred_string_Serialized_state);
871
32
    R_set_altrep_Inspect_method(cls, deferred_string_Inspect);
872
32
    R_set_altrep_Length_method(cls, deferred_string_Length);
873
874
    /* override ALTVEC methods */
875
32
    R_set_altvec_Dataptr_method(cls, deferred_string_Dataptr);
876
32
    R_set_altvec_Dataptr_or_null_method(cls, deferred_string_Dataptr_or_null);
877
32
    R_set_altvec_Extract_subset_method(cls, deferred_string_Extract_subset);
878
879
    /* override ALTSTRING methods */
880
32
    R_set_altstring_Elt_method(cls, deferred_string_Elt);
881
32
    R_set_altstring_Set_elt_method(cls, deferred_string_Set_elt);
882
32
    R_set_altstring_Is_sorted_method(cls, deferred_string_Is_sorted);
883
32
    R_set_altstring_No_NA_method(cls, deferred_string_No_NA);
884
32
}
885
886
887
/*
888
 * Constructor
889
 */
890
891
attribute_hidden SEXP R_deferred_coerceToString(SEXP v, SEXP info)
892
259k
{
893
259k
    SEXP ans = R_NilValue;
894
259k
    switch (TYPEOF(v)) {
895
258k
    case INTSXP:
896
259k
    case REALSXP:
897
259k
  PROTECT(v); /* may not be needed, but to be safe ... */
898
259k
  if (info == NULL) {
899
259k
      PrintDefaults(); /* to set R_print from options */
900
259k
      info = ScalarInteger(R_print.scipen);
901
259k
      if (strcmp(OutDec, ".")) {
902
    /* non-default OutDec setting -- attach as an attribute */
903
81
    PROTECT(info);
904
81
    if (R_OutDecSym == NULL)
905
0
        R_OutDecSym = install("OutDec");
906
81
    setAttrib(info, R_OutDecSym, GetOption1(R_OutDecSym));
907
81
    UNPROTECT(1); /* info */
908
81
      }
909
259k
  }
910
259k
  MARK_NOT_MUTABLE(v); /* make sure it can't change once captured */
911
259k
  ans = PROTECT(MAKE_DEFERRED_STRING_STATE(v, info));
912
259k
  ans = R_new_altrep(R_deferred_string_class, ans, R_NilValue);
913
259k
  UNPROTECT(2); /* ans, v */
914
259k
  break;
915
0
    default:
916
0
  error("unsupported type for deferred string coercion");
917
259k
    }
918
259k
    return ans;
919
259k
}
920
921
922
/**
923
 ** Memory Mapped Vectors
924
 **/
925
926
/* For now, this code is designed to work both in base R and in a
927
   package. Some simplifications would be possible if it was only to
928
   be used in base. in particular, the issue of finalizing objects
929
   before unloading the library would not need to be addressed, and
930
   ordinary finalizers in the external pointers could be used instead
931
   of maintaining a weak reference list of the live mmap objects. */
932
933
/*
934
 * MMAP Object State
935
 */
936
937
/* State is held in a LISTSXP of length 3, and includes
938
   
939
       file
940
       size and length in a REALSXP
941
       type, ptrOK, wrtOK, serOK in an INTSXP
942
943
   These are used by the methods, and also represent the serialized
944
   state object.
945
 */
946
947
#ifndef Win32
948
static SEXP make_mmap_state(SEXP file, size_t size, int type,
949
          Rboolean ptrOK, Rboolean wrtOK, Rboolean serOK)
950
0
{
951
0
    SEXP sizes = PROTECT(allocVector(REALSXP, 2));
952
0
    double *dsizes = REAL(sizes);
953
0
    dsizes[0] = size;
954
0
    switch(type) {
955
0
    case INTSXP: dsizes[1] = size / sizeof(int); break;
956
0
    case REALSXP: dsizes[1] = size / sizeof(double); break;
957
0
    default: error("mmap for %s not supported yet", type2char(type));
958
0
    }
959
960
0
    SEXP info = PROTECT(allocVector(INTSXP, 4));
961
0
    INTEGER(info)[0] = type;
962
0
    INTEGER(info)[1] = ptrOK;
963
0
    INTEGER(info)[2] = wrtOK;
964
0
    INTEGER(info)[3] = serOK;
965
966
0
    SEXP state = list3(file, sizes, info);
967
968
0
    UNPROTECT(2);
969
0
    return state;
970
0
}
971
#endif
972
973
0
#define MMAP_STATE_FILE(x) CAR(x)
974
0
#define MMAP_STATE_SIZE(x) ((size_t) REAL_ELT(CADR(x), 0))
975
0
#define MMAP_STATE_LENGTH(x) ((size_t) REAL_ELT(CADR(x), 1))
976
0
#define MMAP_STATE_TYPE(x) INTEGER(CADDR(x))[0]
977
0
#define MMAP_STATE_PTROK(x) INTEGER(CADDR(x))[1]
978
0
#define MMAP_STATE_WRTOK(x) INTEGER(CADDR(x))[2]
979
0
#define MMAP_STATE_SEROK(x) INTEGER(CADDR(x))[3]
980
981
982
/*
983
 * MMAP Classes and Objects
984
 */
985
986
static R_altrep_class_t mmap_integer_class;
987
static R_altrep_class_t mmap_real_class;
988
989
/* MMAP objects are ALTREP objects with data fields
990
991
       data1: an external pointer to the mmaped address
992
       data2: the MMAP object's state
993
994
   The state is also stored in the Protected field of the external
995
   pointer for use by the finalizer.
996
*/
997
998
#ifndef Win32
999
static void register_mmap_eptr(SEXP eptr);
1000
static SEXP make_mmap(void *p, SEXP file, size_t size, int type,
1001
          Rboolean ptrOK, Rboolean wrtOK, Rboolean serOK)
1002
0
{
1003
0
    SEXP state = PROTECT(make_mmap_state(file, size,
1004
0
           type, ptrOK, wrtOK, serOK));
1005
0
    SEXP eptr = PROTECT(R_MakeExternalPtr(p, R_NilValue, state));
1006
0
    register_mmap_eptr(eptr);
1007
1008
0
    R_altrep_class_t class;
1009
0
    switch(type) {
1010
0
    case INTSXP:
1011
0
  class = mmap_integer_class;
1012
0
  break;
1013
0
    case REALSXP:
1014
0
  class = mmap_real_class;
1015
0
  break;
1016
0
    default: error("mmap for %s not supported yet", type2char(type));
1017
0
    }
1018
1019
0
    SEXP ans = R_new_altrep(class, eptr, state);
1020
0
    if (ptrOK && ! wrtOK)
1021
0
  MARK_NOT_MUTABLE(ans);
1022
1023
0
    UNPROTECT(2); /* state, eptr */
1024
0
    return ans;
1025
0
}
1026
#endif
1027
1028
0
#define MMAP_EPTR(x) R_altrep_data1(x)
1029
0
#define MMAP_STATE(x) R_altrep_data2(x)
1030
0
#define MMAP_LENGTH(x) MMAP_STATE_LENGTH(MMAP_STATE(x))
1031
0
#define MMAP_PTROK(x) MMAP_STATE_PTROK(MMAP_STATE(x))
1032
0
#define MMAP_WRTOK(x) MMAP_STATE_WRTOK(MMAP_STATE(x))
1033
0
#define MMAP_SEROK(x) MMAP_STATE_SEROK(MMAP_STATE(x))
1034
1035
#define MMAP_EPTR_STATE(x) R_ExternalPtrProtected(x)
1036
1037
static R_INLINE void *MMAP_ADDR(SEXP x)
1038
0
{
1039
0
    SEXP eptr = MMAP_EPTR(x);
1040
0
    void *addr = R_ExternalPtrAddr(eptr);
1041
1042
0
    if (addr == NULL)
1043
0
  error("object has been unmapped");
1044
0
    return addr;
1045
0
}
1046
1047
/* We need to maintain a list of weak references to the external
1048
   pointers of memory-mapped objects so a request to unload the shared
1049
   library can finalize them before unloading; otherwise, attempting
1050
   to run a finalizer after unloading would result in an illegal
1051
   instruction. */
1052
1053
1054
#ifndef Win32
1055
static SEXP mmap_list = NULL;
1056
1057
0
#define MAXCOUNT 10
1058
1059
static void mmap_finalize(SEXP eptr);
1060
static void register_mmap_eptr(SEXP eptr)
1061
0
{
1062
0
    if (mmap_list == NULL) {
1063
0
  mmap_list = CONS(R_NilValue, R_NilValue);
1064
0
  R_PreserveObject(mmap_list);
1065
0
    }
1066
    
1067
    /* clean out the weak list every MAXCOUNT calls*/
1068
0
    static int cleancount = MAXCOUNT;
1069
0
    if (--cleancount <= 0) {
1070
0
  cleancount = MAXCOUNT;
1071
0
  for (SEXP last = mmap_list, next = CDR(mmap_list);
1072
0
       next != R_NilValue;
1073
0
       next = CDR(next))
1074
0
      if (R_WeakRefKey(CAR(next)) == R_NilValue)
1075
0
    SETCDR(last, CDR(next));
1076
0
      else
1077
0
    last = next;
1078
0
    }
1079
1080
    /* add a weak reference with a finalizer to the list */
1081
0
    SETCDR(mmap_list, 
1082
0
     CONS(R_MakeWeakRefC(eptr, R_NilValue, mmap_finalize, TRUE),
1083
0
    CDR(mmap_list)));
1084
1085
    /* store the weak reference in the external pointer for do_munmap_file */
1086
0
    R_SetExternalPtrTag(eptr, CAR(CDR(mmap_list)));
1087
0
}
1088
#endif
1089
1090
#ifdef SIMPLEMMAP
1091
static void finalize_mmap_objects()
1092
{
1093
    if (mmap_list == NULL)
1094
  return;
1095
    
1096
    /* finalize any remaining mmap objects before unloading */
1097
    for (SEXP next = CDR(mmap_list); next != R_NilValue; next = CDR(next))
1098
  R_RunWeakRefFinalizer(CAR(next));
1099
    R_ReleaseObject(mmap_list);
1100
}
1101
#endif
1102
1103
1104
/*
1105
 * ALTREP Methods
1106
 */
1107
1108
static SEXP mmap_Serialized_state(SEXP x)
1109
0
{
1110
    /* If serOK is FALSE then serialize as a regular typed vector. If
1111
       serOK is true, then serialize information to allow the mmap to
1112
       be reconstructed. The original file name is serialized; it will
1113
       be expanded again when unserializing, in a context where the
1114
       result may be different. */
1115
0
    if (MMAP_SEROK(x))
1116
0
  return MMAP_STATE(x);
1117
0
    else
1118
0
  return NULL;
1119
0
}
1120
1121
static SEXP mmap_file(SEXP, int, Rboolean, Rboolean, Rboolean, Rboolean);
1122
1123
static SEXP mmap_Unserialize(SEXP class, SEXP state)
1124
0
{
1125
0
    SEXP file = MMAP_STATE_FILE(state);
1126
0
    int type = MMAP_STATE_TYPE(state);
1127
0
    Rboolean ptrOK = (Rboolean) MMAP_STATE_PTROK(state);
1128
0
    Rboolean wrtOK = (Rboolean) MMAP_STATE_WRTOK(state);
1129
0
    Rboolean serOK = (Rboolean) MMAP_STATE_SEROK(state);
1130
1131
0
    SEXP val = mmap_file(file, type, ptrOK, wrtOK, serOK, TRUE);
1132
0
    if (val == NULL) {
1133
  /**** The attempt to memory map failed. Eventually it would be
1134
        good to have a mechanism to allow the user to try to
1135
        resolve this.  For now, return a length zero vector with
1136
        another warning. */
1137
0
  warning("memory mapping failed; returning vector of length zero");
1138
0
  return allocVector(type, 0);
1139
0
    }
1140
0
    return val;
1141
0
}
1142
1143
static Rboolean mmap_Inspect(SEXP x, int pre, int deep, int pvec,
1144
           void (*inspect_subtree)(SEXP, int, int, int))
1145
0
{
1146
0
    Rboolean ptrOK = (Rboolean) MMAP_PTROK(x);
1147
0
    Rboolean wrtOK = (Rboolean) MMAP_WRTOK(x);
1148
0
    Rboolean serOK = (Rboolean) MMAP_SEROK(x);
1149
0
    Rprintf(" mmaped %s", R_typeToChar(x));
1150
0
    Rprintf(" [ptr=%d,wrt=%d,ser=%d]\n", ptrOK, wrtOK, serOK);
1151
0
    return TRUE;
1152
0
}
1153
1154
1155
/*
1156
 * ALTVEC Methods
1157
 */
1158
1159
static R_xlen_t mmap_Length(SEXP x)
1160
0
{
1161
0
    return MMAP_LENGTH(x);
1162
0
}
1163
1164
static void *mmap_Dataptr(SEXP x, Rboolean writeable)
1165
0
{
1166
    /* get addr first to get error if the object has been unmapped */
1167
0
    void *addr = MMAP_ADDR(x);
1168
1169
0
    if (MMAP_PTROK(x))
1170
0
  return addr;
1171
0
    else
1172
0
  error("cannot access data pointer for this mmaped vector");
1173
0
}
1174
1175
static const void *mmap_Dataptr_or_null(SEXP x)
1176
0
{
1177
0
    return MMAP_PTROK(x) ? MMAP_ADDR(x) : NULL;
1178
0
}
1179
1180
1181
/*
1182
 * ALTINTEGER Methods
1183
 */
1184
1185
static int mmap_integer_Elt(SEXP x, R_xlen_t i)
1186
0
{
1187
0
    int *p = MMAP_ADDR(x);
1188
0
    return p[i];
1189
0
}
1190
1191
static
1192
R_xlen_t mmap_integer_Get_region(SEXP sx, R_xlen_t i, R_xlen_t n, int *buf)
1193
0
{
1194
0
    int *x = MMAP_ADDR(sx);
1195
0
    R_xlen_t size = XLENGTH(sx);
1196
0
    R_xlen_t ncopy = size - i > n ? n : size - i;
1197
0
    for (R_xlen_t k = 0; k < ncopy; k++)
1198
0
  buf[k] = x[k + i];
1199
    //memcpy(buf, x + i, ncopy * sizeof(int));
1200
0
    return ncopy;
1201
0
}
1202
1203
1204
/*
1205
 * ALTREAL Methods
1206
 */
1207
1208
static double mmap_real_Elt(SEXP x, R_xlen_t i)
1209
0
{
1210
0
    double *p = MMAP_ADDR(x);
1211
0
    return p[i];
1212
0
}
1213
1214
static
1215
R_xlen_t mmap_real_Get_region(SEXP sx, R_xlen_t i, R_xlen_t n, double *buf)
1216
0
{
1217
0
    double *x = MMAP_ADDR(sx);
1218
0
    R_xlen_t size = XLENGTH(sx);
1219
0
    R_xlen_t ncopy = size - i > n ? n : size - i;
1220
0
    for (R_xlen_t k = 0; k < ncopy; k++)
1221
0
  buf[k] = x[k + i];
1222
    //memcpy(buf, x + i, ncopy * sizeof(double));
1223
0
    return ncopy;
1224
0
}
1225
1226
1227
/*
1228
 * Class Objects and Method Tables
1229
 */
1230
1231
#ifdef SIMPLEMMAP
1232
# define MMAPPKG "simplemmap"
1233
#else
1234
64
# define MMAPPKG "base"
1235
#endif
1236
1237
static void InitMmapIntegerClass(DllInfo *dll)
1238
32
{
1239
32
    R_altrep_class_t cls =
1240
32
  R_make_altinteger_class("mmap_integer", MMAPPKG, dll);
1241
32
    mmap_integer_class = cls;
1242
 
1243
    /* override ALTREP methods */
1244
32
    R_set_altrep_Unserialize_method(cls, mmap_Unserialize);
1245
32
    R_set_altrep_Serialized_state_method(cls, mmap_Serialized_state);
1246
32
    R_set_altrep_Inspect_method(cls, mmap_Inspect);
1247
32
    R_set_altrep_Length_method(cls, mmap_Length);
1248
1249
    /* override ALTVEC methods */
1250
32
    R_set_altvec_Dataptr_method(cls, mmap_Dataptr);
1251
32
    R_set_altvec_Dataptr_or_null_method(cls, mmap_Dataptr_or_null);
1252
1253
    /* override ALTINTEGER methods */
1254
32
    R_set_altinteger_Elt_method(cls, mmap_integer_Elt);
1255
32
    R_set_altinteger_Get_region_method(cls, mmap_integer_Get_region);
1256
32
}
1257
1258
static void InitMmapRealClass(DllInfo *dll)
1259
32
{
1260
32
    R_altrep_class_t cls =
1261
32
  R_make_altreal_class("mmap_real", MMAPPKG, dll);
1262
32
    mmap_real_class = cls;
1263
1264
    /* override ALTREP methods */
1265
32
    R_set_altrep_Unserialize_method(cls, mmap_Unserialize);
1266
32
    R_set_altrep_Serialized_state_method(cls, mmap_Serialized_state);
1267
32
    R_set_altrep_Inspect_method(cls, mmap_Inspect);
1268
32
    R_set_altrep_Length_method(cls, mmap_Length);
1269
1270
    /* override ALTVEC methods */
1271
32
    R_set_altvec_Dataptr_method(cls, mmap_Dataptr);
1272
32
    R_set_altvec_Dataptr_or_null_method(cls, mmap_Dataptr_or_null);
1273
1274
    /* override ALTREAL methods */
1275
32
    R_set_altreal_Elt_method(cls, mmap_real_Elt);
1276
32
    R_set_altreal_Get_region_method(cls, mmap_real_Get_region);
1277
32
}
1278
1279
1280
/*
1281
 * Constructor
1282
 */
1283
1284
#ifdef Win32
1285
/* unused
1286
static void mmap_finalize(SEXP eptr)
1287
{
1288
    error("mmap objects not supported on Windows yet");
1289
}
1290
*/
1291
1292
static SEXP mmap_file(SEXP file, int type, Rboolean ptrOK, Rboolean wrtOK,
1293
          Rboolean serOK, Rboolean warn)
1294
{
1295
    error("mmap objects not supported on Windows yet");
1296
}
1297
#else
1298
/* derived from the example in
1299
  https://www.safaribooksonline.com/library/view/linux-system-programming/0596009585/ch04s03.html */
1300
1301
#include <sys/stat.h>
1302
#include <fcntl.h>
1303
#include <errno.h>
1304
#include <unistd.h>
1305
#include <sys/mman.h>
1306
1307
//#define DEBUG_PRINT(x) REprintf(x);
1308
0
#define DEBUG_PRINT(x) do { } while (0)
1309
1310
static void mmap_finalize(SEXP eptr)
1311
0
{
1312
0
    DEBUG_PRINT("finalizing ... ");
1313
0
    void *p = R_ExternalPtrAddr(eptr);
1314
0
    size_t size = MMAP_STATE_SIZE(MMAP_EPTR_STATE(eptr));
1315
1316
0
    if (p != NULL) {
1317
0
  munmap(p, size); /* don't check for errors */
1318
0
  R_SetExternalPtrAddr(eptr, NULL);
1319
0
    }
1320
0
    DEBUG_PRINT("done\n");
1321
0
}
1322
1323
0
#define MMAP_FILE_WARNING_OR_ERROR(str, ...) do { \
1324
0
  if (warn) {         \
1325
0
      warning(str, __VA_ARGS__);     \
1326
0
      return NULL;        \
1327
0
  }           \
1328
0
  else error(str, __VA_ARGS__);     \
1329
0
    } while (0)
1330
      
1331
static SEXP mmap_file(SEXP file, int type, Rboolean ptrOK, Rboolean wrtOK,
1332
          Rboolean serOK, Rboolean warn)
1333
0
{
1334
0
    const char *efn = R_ExpandFileName(translateCharFP(STRING_ELT(file, 0)));
1335
0
    struct stat sb;
1336
1337
    /* Target not link */
1338
0
    if (stat(efn, &sb) != 0)
1339
0
  MMAP_FILE_WARNING_OR_ERROR("stat: %s", strerror(errno));
1340
1341
0
    if (! S_ISREG(sb.st_mode))
1342
0
  MMAP_FILE_WARNING_OR_ERROR("%s is not a regular file", efn);
1343
1344
0
    int oflags = wrtOK ? O_RDWR : O_RDONLY;
1345
0
    int fd = open(efn, oflags);
1346
0
    if (fd == -1)
1347
0
  MMAP_FILE_WARNING_OR_ERROR("open: %s", strerror(errno));
1348
1349
0
    int pflags = wrtOK ? PROT_READ | PROT_WRITE : PROT_READ;
1350
0
    void *p = mmap(0, sb.st_size, pflags, MAP_SHARED, fd, 0);
1351
0
    close(fd); /* don't care if this fails */
1352
0
    if (p == MAP_FAILED)
1353
0
  MMAP_FILE_WARNING_OR_ERROR("mmap: %s", strerror(errno));
1354
1355
0
    return make_mmap(p, file, sb.st_size, type, ptrOK, wrtOK, serOK);
1356
0
}
1357
#endif
1358
1359
static Rboolean asLogicalNA(SEXP x, Rboolean dflt)
1360
0
{
1361
0
    int val = asLogical(x);
1362
0
    return val == NA_LOGICAL ? dflt : (Rboolean) val;
1363
0
}
1364
1365
#ifdef SIMPLEMMAP
1366
SEXP do_mmap_file(SEXP args)
1367
{
1368
    args = CDR(args);
1369
#else
1370
attribute_hidden SEXP do_mmap_file(SEXP call, SEXP op, SEXP args, SEXP env)
1371
0
{
1372
0
#endif
1373
0
    SEXP file = CAR(args);
1374
0
    SEXP stype = CADR(args);
1375
0
    SEXP sptrOK = CADDR(args);
1376
0
    SEXP swrtOK = CADDDR(args);
1377
0
    SEXP sserOK = CAD4R(args);
1378
1379
0
    int type = REALSXP;
1380
0
    if (stype != R_NilValue) {
1381
0
  const char *typestr = CHAR(asChar(stype));
1382
0
  if (strcmp(typestr, "double") == 0)
1383
0
      type = REALSXP;
1384
0
  else if (strcmp(typestr, "integer") == 0 ||
1385
0
     strcmp(typestr, "int") == 0)
1386
0
      type = INTSXP;
1387
0
  else
1388
0
      error("type '%s' is not supported", typestr);
1389
0
    }    
1390
1391
0
    Rboolean ptrOK = sptrOK == R_NilValue ? TRUE : asLogicalNA(sptrOK, FALSE);
1392
0
    Rboolean wrtOK = swrtOK == R_NilValue ? FALSE : asLogicalNA(swrtOK, FALSE);
1393
0
    Rboolean serOK = sserOK == R_NilValue ? FALSE : asLogicalNA(sserOK, FALSE);
1394
1395
0
    if (TYPEOF(file) != STRSXP || LENGTH(file) != 1 || file == NA_STRING)
1396
0
  error("invalud 'file' argument");
1397
1398
0
    return mmap_file(file, type, ptrOK, wrtOK, serOK, FALSE);
1399
0
}
1400
1401
#ifdef SIMPLEMMAP
1402
static SEXP do_munmap_file(SEXP args)
1403
{
1404
    args = CDR(args);
1405
#else
1406
attribute_hidden SEXP do_munmap_file(SEXP call, SEXP op, SEXP args, SEXP env)
1407
0
{
1408
0
#endif
1409
0
    SEXP x = CAR(args);
1410
1411
    /**** would be useful to have R_mmap_class virtual class as parent here */
1412
0
    if (! (R_altrep_inherits(x, mmap_integer_class) ||
1413
0
     R_altrep_inherits(x, mmap_real_class)))
1414
0
  error("not a memory-mapped object");
1415
1416
    /* using the finalizer is a cheat to avoid yet another #ifdef Windows */
1417
0
    SEXP eptr = MMAP_EPTR(x);
1418
0
    errno = 0;
1419
0
    R_RunWeakRefFinalizer(R_ExternalPtrTag(eptr));
1420
0
    if (errno)
1421
0
  error("munmap: %s", strerror(errno));
1422
0
    return R_NilValue;
1423
0
}
1424
1425
1426
/**
1427
 ** Attribute and Meta Data Wrappers
1428
 **/
1429
1430
/*
1431
 * Wrapper Classes and Objects
1432
 */
1433
1434
693k
#define NMETA 2
1435
1436
static R_altrep_class_t wrap_integer_class;
1437
static R_altrep_class_t wrap_logical_class;
1438
static R_altrep_class_t wrap_real_class;
1439
static R_altrep_class_t wrap_complex_class;
1440
static R_altrep_class_t wrap_raw_class;
1441
static R_altrep_class_t wrap_string_class;
1442
static R_altrep_class_t wrap_list_class;
1443
1444
/* Wrapper objects are ALTREP objects designed to hold the attributes
1445
   of a potentially large object and/or meta data for the object. */
1446
1447
2.07M
#define WRAPPER_WRAPPED(x) R_altrep_data1(x)
1448
71.3k
#define WRAPPER_SET_WRAPPED(x, v) R_set_altrep_data1(x, v)
1449
1.04M
#define WRAPPER_METADATA(x) R_altrep_data2(x)
1450
1451
141k
#define WRAPPER_SORTED(x) INTEGER(WRAPPER_METADATA(x))[0]
1452
141k
#define WRAPPER_NO_NA(x) INTEGER(WRAPPER_METADATA(x))[1]
1453
1454
/* When a wrapper is created, e.g. using structure(), the data may
1455
   initially be shared. Once it is modified to be modified or a
1456
   DATAPTR is requested the data has to be remain unchanged and the
1457
   wrapper should be the only reference. The metadata is marked to
1458
   reflecth this. The data then has to be duplicated by the duplicate
1459
   method to ensure that no new references are created. This ensures
1460
   that a DATAPTR, once obtained, remains valid while the wrapper
1461
   object is reachable.
1462
   
1463
   For now the sxpinfo.gp field is used via PRSEEN for the lock.
1464
   Allow for cases where shallow_duplicate() returns a value with
1465
   non-zero REFCNT (e.g. returns a value marked not mutable.
1466
 */
1467
308k
#define WRAPPER_DATA_LOCK(x) PRSEEN(WRAPPER_METADATA(x))
1468
148k
#define WRAPPER_SET_DATA_LOCK(x, v) SET_PRSEEN(WRAPPER_METADATA(x), v)
1469
308k
#define WRAPPER_DATA_IS_LOCKED(x) (WRAPPER_DATA_LOCK(x) > 0)
1470
71.5k
#define WRAPPER_LOCK_DATA(x) WRAPPER_SET_DATA_LOCK(x, 1)
1471
76.6k
#define WRAPPER_UNLOCK_DATA(x) WRAPPER_SET_DATA_LOCK(x, 0)
1472
1473
 
1474
static R_INLINE SEXP WRAPPER_WRAPPED_RW(SEXP x)
1475
308k
{
1476
308k
    SEXP data = WRAPPER_WRAPPED(x);
1477
308k
    if (WRAPPER_DATA_IS_LOCKED(x)) {
1478
  /* Once data is locked it's reference count should remain at one. */
1479
  /* Unless duplicate() doesn't produce a zero reference count object */ 
1480
236k
  if (MAYBE_SHARED(data) && WRAPPER_DATA_LOCK(x) == 1)
1481
0
      error("REFCNT on locked WRAPPER data increased to %d",
1482
0
      REFCNT(data));
1483
236k
    }
1484
71.5k
    else {
1485
  /* If the data might be shared and is accessed for possible
1486
     modification, then it needs to be duplicated now. */
1487
71.5k
  if (MAYBE_SHARED(data)) {
1488
71.3k
      PROTECT(x);
1489
71.3k
      WRAPPER_SET_WRAPPED(x, shallow_duplicate(data));
1490
71.3k
      UNPROTECT(1);
1491
71.3k
      if (REFCNT(WRAPPER_WRAPPED(x)) == 1)
1492
71.3k
    WRAPPER_LOCK_DATA(x);
1493
0
      else
1494
0
    WRAPPER_SET_DATA_LOCK(x, 2);
1495
71.3k
  }
1496
71.5k
  else WRAPPER_LOCK_DATA(x);
1497
71.5k
    }
1498
1499
    /* The meta data also needs to be cleared as it may no longer be
1500
       valid after a write. */
1501
308k
    SEXP meta = WRAPPER_METADATA(x);
1502
308k
    INTEGER(meta)[0] = UNKNOWN_SORTEDNESS;
1503
616k
    for (int i = 1; i < NMETA; i++)
1504
308k
  INTEGER(meta)[i] = 0;
1505
1506
308k
    return WRAPPER_WRAPPED(x);
1507
308k
}
1508
1509
1510
/*
1511
 * ALTREP Methods
1512
 */
1513
1514
static SEXP wrapper_Serialized_state(SEXP x)
1515
0
{
1516
    /* If the wrapped value is not an ALTREP and there is no useful
1517
       metadata then return NULL to allow this to be serialized as a
1518
       standard object. This avoids serializing potentially large
1519
       attributes on the wrapped value (PR18142). */
1520
0
    if (! ALTREP(WRAPPER_WRAPPED(x)) &&
1521
0
  WRAPPER_SORTED(x) == UNKNOWN_SORTEDNESS &&
1522
0
  ! WRAPPER_NO_NA(x))
1523
0
  return NULL;
1524
1525
0
    return CONS(WRAPPER_WRAPPED(x), WRAPPER_METADATA(x));
1526
0
}
1527
1528
static SEXP make_wrapper(SEXP, SEXP);
1529
1530
static SEXP wrapper_Unserialize(SEXP class, SEXP state)
1531
1
{
1532
1
    return make_wrapper(CAR(state), CDR(state));
1533
1
}
1534
1535
static SEXP wrapper_Duplicate(SEXP x, Rboolean deep)
1536
353
{
1537
353
    SEXP data = WRAPPER_WRAPPED(x);
1538
1539
    /* For a deep copy, duplicate the data. */
1540
    /* For a shallow copy, mark as immutable in the NAMED world; with
1541
       reference counting the reference count will be incremented when
1542
       the data is installed in the new wrapper object. */
1543
353
    if (deep || WRAPPER_DATA_IS_LOCKED(x)) // **** shallow duplicate if only locked?
1544
201
  data = duplicate(data);
1545
#ifndef SWITCH_TO_REFCNT
1546
    else
1547
  /* not needed with reference counting */
1548
  MARK_NOT_MUTABLE(data);
1549
#endif
1550
353
    PROTECT(data);
1551
1552
    /* always duplicate the meta data */
1553
353
    SEXP meta = PROTECT(duplicate(WRAPPER_METADATA(x)));
1554
1555
353
    SEXP ans = make_wrapper(data, meta);
1556
1557
353
    UNPROTECT(2); /* data, meta */
1558
353
    return ans;
1559
353
}
1560
1561
static Rboolean wrapper_Inspect(SEXP x, int pre, int deep, int pvec,
1562
        void (*inspect_subtree)(SEXP, int, int, int))
1563
0
{
1564
0
    Rboolean srt = (Rboolean) WRAPPER_SORTED(x);
1565
0
    Rboolean no_na = (Rboolean) WRAPPER_NO_NA(x);
1566
0
    Rboolean lck = (Rboolean) WRAPPER_DATA_IS_LOCKED(x);
1567
0
    Rprintf(" wrapper [srt=%d,no_na=%d,lck=%d]\n", srt, no_na, lck);
1568
0
    inspect_subtree(WRAPPER_WRAPPED(x), pre, deep, pvec);
1569
0
    return TRUE;
1570
0
}
1571
1572
static R_xlen_t wrapper_Length(SEXP x)
1573
917k
{
1574
917k
    return XLENGTH(WRAPPER_WRAPPED(x));
1575
917k
}
1576
1577
1578
/*
1579
 * ALTVEC Methods
1580
 */
1581
1582
static void *wrapper_Dataptr(SEXP x, Rboolean writeable)
1583
202
{
1584
202
    if (writeable)
1585
202
  return DATAPTR_RW(WRAPPER_WRAPPED_RW(x));
1586
0
    else
1587
  /* This has to use WRAPPER_WRAPPED_RW even for a read-only
1588
     pointer to make sure a later request for a writable pointer
1589
     will return the same address. */
1590
  /**** could avoid the cast by having separate methods */
1591
0
  return (void *) DATAPTR_RO(WRAPPER_WRAPPED_RW(x));
1592
202
}
1593
1594
static const void *wrapper_Dataptr_or_null(SEXP x)
1595
231
{
1596
    /* This has to use WRAPPER_WRAPPED_RW as above. */
1597
231
    return DATAPTR_OR_NULL(WRAPPER_WRAPPED_RW(x));
1598
231
}
1599
1600
static SEXP wrapper_Extract_subset(SEXP x, SEXP indx, SEXP call)
1601
103
{
1602
103
  return ExtractSubset(WRAPPER_WRAPPED(x), indx, call);
1603
103
}
1604
1605
1606
/*
1607
 * ALTINTEGER Methods
1608
 */
1609
1610
static int wrapper_integer_Elt(SEXP x, R_xlen_t i)
1611
8.55k
{
1612
8.55k
    return INTEGER_ELT(WRAPPER_WRAPPED(x), i);
1613
8.55k
}
1614
1615
static
1616
R_xlen_t wrapper_integer_Get_region(SEXP x, R_xlen_t i, R_xlen_t n, int *buf)
1617
0
{
1618
0
    return INTEGER_GET_REGION(WRAPPER_WRAPPED(x), i, n, buf);
1619
0
}
1620
1621
static int wrapper_integer_Is_sorted(SEXP x)
1622
0
{
1623
0
    if (WRAPPER_SORTED(x) != UNKNOWN_SORTEDNESS)
1624
0
  return WRAPPER_SORTED(x);
1625
0
    else
1626
  /* If the  meta data bit is not set, defer to the wrapped object. */
1627
0
  return INTEGER_IS_SORTED(WRAPPER_WRAPPED(x));
1628
0
}
1629
1630
static int wrapper_integer_no_NA(SEXP x)
1631
0
{
1632
0
    if (WRAPPER_NO_NA(x))
1633
0
  return TRUE;
1634
0
    else
1635
  /* If the  meta data bit is not set, defer to the wrapped object. */
1636
0
  return INTEGER_NO_NA(WRAPPER_WRAPPED(x));
1637
0
}
1638
1639
1640
/*
1641
 * ALTLOGICAL Methods
1642
 */
1643
1644
static int wrapper_logical_Elt(SEXP x, R_xlen_t i)
1645
0
{
1646
0
    return LOGICAL_ELT(WRAPPER_WRAPPED(x), i);
1647
0
}
1648
1649
static
1650
R_xlen_t wrapper_logical_Get_region(SEXP x, R_xlen_t i, R_xlen_t n, int *buf)
1651
0
{
1652
0
    return LOGICAL_GET_REGION(WRAPPER_WRAPPED(x), i, n, buf);
1653
0
}
1654
1655
static int wrapper_logical_Is_sorted(SEXP x)
1656
0
{
1657
0
    if (WRAPPER_SORTED(x) != UNKNOWN_SORTEDNESS)
1658
0
  return WRAPPER_SORTED(x);
1659
0
    else
1660
  /* If the  meta data bit is not set, defer to the wrapped object. */
1661
0
  return LOGICAL_IS_SORTED(WRAPPER_WRAPPED(x));
1662
0
}
1663
1664
static int wrapper_logical_no_NA(SEXP x)
1665
0
{
1666
0
    if (WRAPPER_NO_NA(x))
1667
0
  return TRUE;
1668
0
    else
1669
  /* If the  meta data bit is not set, defer to the wrapped object. */
1670
0
  return LOGICAL_NO_NA(WRAPPER_WRAPPED(x));
1671
0
}
1672
1673
1674
/*
1675
 * ALTREAL Methods
1676
 */
1677
1678
static double wrapper_real_Elt(SEXP x, R_xlen_t i)
1679
24.8k
{
1680
24.8k
    return REAL_ELT(WRAPPER_WRAPPED(x), i);
1681
24.8k
}
1682
1683
static
1684
R_xlen_t wrapper_real_Get_region(SEXP x, R_xlen_t i, R_xlen_t n, double *buf)
1685
0
{
1686
0
    return REAL_GET_REGION(WRAPPER_WRAPPED(x), i, n, buf);
1687
0
}
1688
1689
static int wrapper_real_Is_sorted(SEXP x)
1690
0
{
1691
0
    if (WRAPPER_SORTED(x) != UNKNOWN_SORTEDNESS)
1692
0
  return WRAPPER_SORTED(x);
1693
0
    else
1694
  /* If the  meta data bit is not set, defer to the wrapped object. */
1695
0
  return REAL_IS_SORTED(WRAPPER_WRAPPED(x));
1696
0
}
1697
1698
static int wrapper_real_no_NA(SEXP x)
1699
0
{
1700
0
    if (WRAPPER_NO_NA(x))
1701
0
  return TRUE;
1702
0
    else
1703
  /* If the  meta data bit is not set, defer to the wrapped object. */
1704
0
  return REAL_NO_NA(WRAPPER_WRAPPED(x));
1705
0
}
1706
1707
1708
/*
1709
 * ALTCOMPLEX Methods
1710
 */
1711
1712
static Rcomplex wrapper_complex_Elt(SEXP x, R_xlen_t i)
1713
0
{
1714
0
    return COMPLEX_ELT(WRAPPER_WRAPPED(x), i);
1715
0
}
1716
1717
static
1718
R_xlen_t wrapper_complex_Get_region(SEXP x, R_xlen_t i, R_xlen_t n,
1719
            Rcomplex *buf)
1720
0
{
1721
0
    return COMPLEX_GET_REGION(WRAPPER_WRAPPED(x), i, n, buf);
1722
0
}
1723
1724
1725
/*
1726
 * ALTRAW Methods
1727
 */
1728
1729
static Rbyte wrapper_raw_Elt(SEXP x, R_xlen_t i)
1730
0
{
1731
0
    return RAW_ELT(WRAPPER_WRAPPED(x), i);
1732
0
}
1733
1734
static
1735
R_xlen_t wrapper_raw_Get_region(SEXP x, R_xlen_t i, R_xlen_t n, Rbyte *buf)
1736
0
{
1737
0
    return RAW_GET_REGION(WRAPPER_WRAPPED(x), i, n, buf);
1738
0
}
1739
1740
1741
/*
1742
 * ALTSTRING Methods
1743
 */
1744
1745
static SEXP wrapper_string_Elt(SEXP x, R_xlen_t i)
1746
111k
{
1747
111k
    return STRING_ELT(WRAPPER_WRAPPED(x), i);
1748
111k
}
1749
1750
static void wrapper_string_Set_elt(SEXP x, R_xlen_t i, SEXP v)
1751
130k
{
1752
130k
    SET_STRING_ELT(WRAPPER_WRAPPED_RW(x), i, v);
1753
130k
}
1754
1755
static int wrapper_string_Is_sorted(SEXP x)
1756
0
{
1757
0
    if (WRAPPER_SORTED(x) != UNKNOWN_SORTEDNESS)
1758
0
  return WRAPPER_SORTED(x);
1759
0
    else
1760
  /* If the  meta data bit is not set, defer to the wrapped object. */
1761
0
  return STRING_IS_SORTED(WRAPPER_WRAPPED(x));
1762
0
}
1763
1764
static int wrapper_string_no_NA(SEXP x)
1765
0
{
1766
0
    if (WRAPPER_NO_NA(x))
1767
0
  return TRUE;
1768
0
    else
1769
  /* If the  meta data bit is not set, defer to the wrapped object. */
1770
0
  return STRING_NO_NA(WRAPPER_WRAPPED(x));
1771
0
}
1772
1773
1774
/*
1775
 * ALTLIST Methods
1776
 */
1777
1778
static SEXP wrapper_list_Elt(SEXP x, R_xlen_t i)
1779
177k
{
1780
177k
    return VECTOR_ELT(WRAPPER_WRAPPED(x), i);
1781
177k
}
1782
1783
static void wrapper_list_Set_elt(SEXP x, R_xlen_t i, SEXP v)
1784
177k
{
1785
177k
    SET_VECTOR_ELT(WRAPPER_WRAPPED_RW(x), i, v);
1786
177k
}
1787
1788
/*
1789
 * Class Objects and Method Tables
1790
 */
1791
1792
224
#define WRAPPKG "base"
1793
1794
static void InitWrapIntegerClass(DllInfo *dll)
1795
32
{
1796
32
    R_altrep_class_t cls =
1797
32
  R_make_altinteger_class("wrap_integer", WRAPPKG, dll);
1798
32
    wrap_integer_class = cls;
1799
 
1800
    /* override ALTREP methods */
1801
32
    R_set_altrep_Unserialize_method(cls, wrapper_Unserialize);
1802
32
    R_set_altrep_Serialized_state_method(cls, wrapper_Serialized_state);
1803
32
    R_set_altrep_Duplicate_method(cls, wrapper_Duplicate);
1804
32
    R_set_altrep_Inspect_method(cls, wrapper_Inspect);
1805
32
    R_set_altrep_Length_method(cls, wrapper_Length);
1806
1807
    /* override ALTVEC methods */
1808
32
    R_set_altvec_Dataptr_method(cls, wrapper_Dataptr);
1809
32
    R_set_altvec_Dataptr_or_null_method(cls, wrapper_Dataptr_or_null);
1810
32
    R_set_altvec_Extract_subset_method(cls, wrapper_Extract_subset);
1811
1812
    /* override ALTINTEGER methods */
1813
32
    R_set_altinteger_Elt_method(cls, wrapper_integer_Elt);
1814
32
    R_set_altinteger_Get_region_method(cls, wrapper_integer_Get_region);
1815
32
    R_set_altinteger_Is_sorted_method(cls, wrapper_integer_Is_sorted);
1816
32
    R_set_altinteger_No_NA_method(cls, wrapper_integer_no_NA);
1817
32
}
1818
1819
static void InitWrapLogicalClass(DllInfo *dll)
1820
32
{
1821
32
    R_altrep_class_t cls =
1822
32
  R_make_altlogical_class("wrap_logical", WRAPPKG, dll);
1823
32
    wrap_logical_class = cls;
1824
 
1825
    /* override ALTREP methods */
1826
32
    R_set_altrep_Unserialize_method(cls, wrapper_Unserialize);
1827
32
    R_set_altrep_Serialized_state_method(cls, wrapper_Serialized_state);
1828
32
    R_set_altrep_Duplicate_method(cls, wrapper_Duplicate);
1829
32
    R_set_altrep_Inspect_method(cls, wrapper_Inspect);
1830
32
    R_set_altrep_Length_method(cls, wrapper_Length);
1831
1832
    /* override ALTVEC methods */
1833
32
    R_set_altvec_Dataptr_method(cls, wrapper_Dataptr);
1834
32
    R_set_altvec_Dataptr_or_null_method(cls, wrapper_Dataptr_or_null);
1835
32
    R_set_altvec_Extract_subset_method(cls, wrapper_Extract_subset);
1836
1837
    /* override ALTLOGICAL methods */
1838
32
    R_set_altlogical_Elt_method(cls, wrapper_logical_Elt);
1839
32
    R_set_altlogical_Get_region_method(cls, wrapper_logical_Get_region);
1840
32
    R_set_altlogical_Is_sorted_method(cls, wrapper_logical_Is_sorted);
1841
32
    R_set_altlogical_No_NA_method(cls, wrapper_logical_no_NA);
1842
32
}
1843
1844
static void InitWrapRealClass(DllInfo *dll)
1845
32
{
1846
32
    R_altrep_class_t cls =
1847
32
  R_make_altreal_class("wrap_real", WRAPPKG, dll);
1848
32
    wrap_real_class = cls;
1849
 
1850
    /* override ALTREP methods */
1851
32
    R_set_altrep_Unserialize_method(cls, wrapper_Unserialize);
1852
32
    R_set_altrep_Serialized_state_method(cls, wrapper_Serialized_state);
1853
32
    R_set_altrep_Duplicate_method(cls, wrapper_Duplicate);
1854
32
    R_set_altrep_Inspect_method(cls, wrapper_Inspect);
1855
32
    R_set_altrep_Length_method(cls, wrapper_Length);
1856
1857
    /* override ALTVEC methods */
1858
32
    R_set_altvec_Dataptr_method(cls, wrapper_Dataptr);
1859
32
    R_set_altvec_Dataptr_or_null_method(cls, wrapper_Dataptr_or_null);
1860
32
    R_set_altvec_Extract_subset_method(cls, wrapper_Extract_subset);
1861
1862
    /* override ALTREAL methods */
1863
32
    R_set_altreal_Elt_method(cls, wrapper_real_Elt);
1864
32
    R_set_altreal_Get_region_method(cls, wrapper_real_Get_region);
1865
32
    R_set_altreal_Is_sorted_method(cls, wrapper_real_Is_sorted);
1866
32
    R_set_altreal_No_NA_method(cls, wrapper_real_no_NA);
1867
32
}
1868
1869
static void InitWrapComplexClass(DllInfo *dll)
1870
32
{
1871
32
    R_altrep_class_t cls =
1872
32
  R_make_altcomplex_class("wrap_complex", WRAPPKG, dll);
1873
32
    wrap_complex_class = cls;
1874
 
1875
    /* override ALTREP methods */
1876
32
    R_set_altrep_Unserialize_method(cls, wrapper_Unserialize);
1877
32
    R_set_altrep_Serialized_state_method(cls, wrapper_Serialized_state);
1878
32
    R_set_altrep_Duplicate_method(cls, wrapper_Duplicate);
1879
32
    R_set_altrep_Inspect_method(cls, wrapper_Inspect);
1880
32
    R_set_altrep_Length_method(cls, wrapper_Length);
1881
1882
    /* override ALTVEC methods */
1883
32
    R_set_altvec_Dataptr_method(cls, wrapper_Dataptr);
1884
32
    R_set_altvec_Dataptr_or_null_method(cls, wrapper_Dataptr_or_null);
1885
32
    R_set_altvec_Extract_subset_method(cls, wrapper_Extract_subset);
1886
1887
    /* override ALTCOMPLEX methods */
1888
32
    R_set_altcomplex_Elt_method(cls, wrapper_complex_Elt);
1889
32
    R_set_altcomplex_Get_region_method(cls, wrapper_complex_Get_region);
1890
32
}
1891
1892
static void InitWrapRawClass(DllInfo *dll)
1893
32
{
1894
32
    R_altrep_class_t cls =
1895
32
  R_make_altraw_class("wrap_raw", WRAPPKG, dll);
1896
32
    wrap_raw_class = cls;
1897
 
1898
    /* override ALTREP methods */
1899
32
    R_set_altrep_Unserialize_method(cls, wrapper_Unserialize);
1900
32
    R_set_altrep_Serialized_state_method(cls, wrapper_Serialized_state);
1901
32
    R_set_altrep_Duplicate_method(cls, wrapper_Duplicate);
1902
32
    R_set_altrep_Inspect_method(cls, wrapper_Inspect);
1903
32
    R_set_altrep_Length_method(cls, wrapper_Length);
1904
1905
    /* override ALTVEC methods */
1906
32
    R_set_altvec_Dataptr_method(cls, wrapper_Dataptr);
1907
32
    R_set_altvec_Dataptr_or_null_method(cls, wrapper_Dataptr_or_null);
1908
32
    R_set_altvec_Extract_subset_method(cls, wrapper_Extract_subset);
1909
1910
    /* override ALTRAW methods */
1911
32
    R_set_altraw_Elt_method(cls, wrapper_raw_Elt);
1912
32
    R_set_altraw_Get_region_method(cls, wrapper_raw_Get_region);
1913
32
}
1914
1915
static void InitWrapStringClass(DllInfo *dll)
1916
32
{
1917
32
    R_altrep_class_t cls =
1918
32
  R_make_altstring_class("wrap_string", WRAPPKG, dll);
1919
32
    wrap_string_class = cls;
1920
 
1921
    /* override ALTREP methods */
1922
32
    R_set_altrep_Unserialize_method(cls, wrapper_Unserialize);
1923
32
    R_set_altrep_Serialized_state_method(cls, wrapper_Serialized_state);
1924
32
    R_set_altrep_Duplicate_method(cls, wrapper_Duplicate);
1925
32
    R_set_altrep_Inspect_method(cls, wrapper_Inspect);
1926
32
    R_set_altrep_Length_method(cls, wrapper_Length);
1927
1928
    /* override ALTVEC methods */
1929
32
    R_set_altvec_Dataptr_method(cls, wrapper_Dataptr);
1930
32
    R_set_altvec_Dataptr_or_null_method(cls, wrapper_Dataptr_or_null);
1931
32
    R_set_altvec_Extract_subset_method(cls, wrapper_Extract_subset);
1932
1933
    /* override ALTSTRING methods */
1934
32
    R_set_altstring_Elt_method(cls, wrapper_string_Elt);
1935
32
    R_set_altstring_Set_elt_method(cls, wrapper_string_Set_elt);
1936
32
    R_set_altstring_Is_sorted_method(cls, wrapper_string_Is_sorted);
1937
32
    R_set_altstring_No_NA_method(cls, wrapper_string_no_NA);
1938
32
}
1939
1940
static void InitWrapListClass(DllInfo *dll)
1941
32
{
1942
32
    R_altrep_class_t cls =
1943
32
  R_make_altlist_class("wrap_list", WRAPPKG, dll);
1944
32
    wrap_list_class = cls;
1945
1946
    /* override ALTREP methods */
1947
32
    R_set_altrep_Unserialize_method(cls, wrapper_Unserialize);
1948
32
    R_set_altrep_Serialized_state_method(cls, wrapper_Serialized_state);
1949
32
    R_set_altrep_Duplicate_method(cls, wrapper_Duplicate);
1950
32
    R_set_altrep_Inspect_method(cls, wrapper_Inspect);
1951
32
    R_set_altrep_Length_method(cls, wrapper_Length);
1952
1953
    /* override ALTVEC methods */
1954
32
    R_set_altvec_Dataptr_method(cls, wrapper_Dataptr);
1955
32
    R_set_altvec_Dataptr_or_null_method(cls, wrapper_Dataptr_or_null);
1956
32
    R_set_altvec_Extract_subset_method(cls, wrapper_Extract_subset);
1957
1958
    /* override ALTLIST methods */
1959
32
    R_set_altlist_Elt_method(cls, wrapper_list_Elt);
1960
32
    R_set_altlist_Set_elt_method(cls, wrapper_list_Set_elt);
1961
32
}
1962
1963
1964
/*
1965
 * Constructor
1966
 */
1967
1968
static SEXP make_wrapper(SEXP x, SEXP meta)
1969
76.6k
{
1970
    /* If x is itself a wrapper it might be a good idea to fuse */
1971
76.6k
    R_altrep_class_t cls;
1972
76.6k
    switch(TYPEOF(x)) {
1973
3.28k
    case INTSXP: cls = wrap_integer_class; break;
1974
0
    case LGLSXP: cls = wrap_logical_class; break;
1975
1.91k
    case REALSXP: cls = wrap_real_class; break;
1976
0
    case CPLXSXP: cls = wrap_complex_class; break;
1977
0
    case RAWSXP: cls = wrap_raw_class; break;
1978
579
    case STRSXP: cls = wrap_string_class; break;
1979
70.8k
    case VECSXP: cls = wrap_list_class; break;
1980
0
    default: error("unsupported type");
1981
76.6k
    }
1982
1983
76.6k
    SEXP ans = R_new_altrep(cls, x, meta);
1984
1985
76.6k
#define WRAPATTRIB
1986
76.6k
#ifdef WRAPATTRIB
1987
76.6k
    if (ATTRIB(x) != R_NilValue) {
1988
  /* could just move attributes if there are no references to x */
1989
71.0k
  PROTECT(ans);
1990
71.0k
  SET_ATTRIB(ans, shallow_duplicate(ATTRIB(x)));
1991
71.0k
  SET_OBJECT(ans, OBJECT(x));
1992
71.0k
  IS_S4_OBJECT(x) ? SET_S4_OBJECT(ans) : UNSET_S4_OBJECT(ans);
1993
71.0k
  UNPROTECT(1); /* ans */
1994
71.0k
    }
1995
76.6k
#endif
1996
1997
#ifndef SWITCH_TO_REFCNT
1998
    if (MAYBE_REFERENCED(x))
1999
  /* make sure no mutation can happen through another reference */
2000
  MARK_NOT_MUTABLE(x);
2001
#endif
2002
2003
76.6k
    WRAPPER_UNLOCK_DATA(ans);
2004
76.6k
    return ans;
2005
76.6k
}
2006
2007
static R_INLINE int is_wrapper(SEXP x)
2008
219k
{
2009
219k
    if (ALTREP(x))
2010
143k
  switch(TYPEOF(x)) {
2011
182
  case INTSXP: return R_altrep_inherits(x, wrap_integer_class);
2012
0
  case LGLSXP: return R_altrep_inherits(x, wrap_logical_class);
2013
401
  case REALSXP: return R_altrep_inherits(x, wrap_real_class);
2014
0
  case CPLXSXP: return R_altrep_inherits(x, wrap_complex_class);
2015
0
  case RAWSXP: return R_altrep_inherits(x, wrap_raw_class);
2016
1.63k
  case STRSXP: return R_altrep_inherits(x, wrap_string_class);
2017
141k
  case VECSXP: return R_altrep_inherits(x, wrap_list_class);
2018
0
  default: return FALSE;
2019
143k
  }
2020
76.3k
    else return FALSE;
2021
219k
}
2022
2023
static SEXP wrap_meta(SEXP x, int srt, int no_na)
2024
76.4k
{
2025
76.4k
    switch(TYPEOF(x)) {
2026
3.28k
    case INTSXP:
2027
5.19k
    case REALSXP:
2028
5.19k
    case LGLSXP:
2029
5.19k
    case CPLXSXP:
2030
5.19k
    case RAWSXP:
2031
5.57k
    case STRSXP:
2032
76.4k
    case VECSXP: break;
2033
0
    default: return x;
2034
76.4k
    }
2035
2036
    /* avoid wrappers of wrappers, at least in some cases */
2037
76.4k
    if (is_wrapper(x) && srt == UNKNOWN_SORTEDNESS && no_na == FALSE)
2038
152
  return shallow_duplicate(x);
2039
2040
#ifndef WRAPATTRIB
2041
    if (ATTRIB(x) != R_NilValue)
2042
  /* For objects without references we could move the attributes
2043
     to the wrapper. For objects with references the attributes
2044
     would have to be shallow duplicated at least. The object/S4
2045
     bits would need to be moved as well. */
2046
  /* For now, just return the original object. */
2047
  return x;
2048
#endif
2049
2050
76.3k
    if (!KNOWN_SORTED(srt) && srt != KNOWN_UNSORTED &&
2051
71.6k
  srt != UNKNOWN_SORTEDNESS)
2052
0
  error("srt must be -2, -1, 0, or +1, +2, or NA");
2053
    
2054
76.3k
    if (no_na < 0 || no_na > 1)
2055
0
  error("no_na must be 0 or +1");
2056
2057
76.3k
    SEXP meta = allocVector(INTSXP, NMETA);
2058
76.3k
    INTEGER(meta)[0] = srt;
2059
76.3k
    INTEGER(meta)[1] = no_na;
2060
2061
76.3k
    return make_wrapper(x, meta);
2062
76.4k
}
2063
2064
attribute_hidden SEXP do_wrap_meta(SEXP call, SEXP op, SEXP args, SEXP env)
2065
4.62k
{
2066
4.62k
    checkArity(op, args);
2067
4.62k
    SEXP x = CAR(args);
2068
4.62k
    int srt = asInteger(CADR(args));
2069
4.62k
    int no_na = asInteger(CADDR(args));
2070
4.62k
    return wrap_meta(x, srt, no_na);
2071
4.62k
}
2072
2073
/*attribute_hidden*/ SEXP R_tryWrap(SEXP x)
2074
71.8k
{
2075
71.8k
    return wrap_meta(x, UNKNOWN_SORTEDNESS, FALSE);
2076
71.8k
}
2077
2078
attribute_hidden SEXP do_tryWrap(SEXP call, SEXP op, SEXP args, SEXP env)
2079
0
{
2080
0
    checkArity(op, args);
2081
0
    SEXP x = CAR(args);
2082
0
    return R_tryWrap(x);
2083
0
}
2084
2085
/* When a wrapper has no useful meta-data, is no longer referenced
2086
   anywhere, and its data is only accessible from the wrapper, then
2087
   the wrapper can be unwrapped to its wrapped data, and its
2088
   attributes can be transferred to the data.
2089
2090
   It is ESSENTIAL that the wrapper no longer be accessed after
2091
   this function is called!
2092
2093
   This function can be used at the end of a complex assignment
2094
   operation. It could be used in other places, but extreme caution is
2095
   needed to make sure there is no possibility that the wrapper object
2096
   will be referenced from C code after it is cleared. */
2097
attribute_hidden SEXP R_tryUnwrap(SEXP x)
2098
143k
{
2099
143k
    if (! MAYBE_SHARED(x) && is_wrapper(x) &&
2100
141k
  WRAPPER_SORTED(x) == UNKNOWN_SORTEDNESS && ! WRAPPER_NO_NA(x)) {
2101
141k
  SEXP data = WRAPPER_WRAPPED(x);
2102
141k
  if (! MAYBE_SHARED(data)) {
2103
70.7k
      SET_ATTRIB(data, ATTRIB(x));
2104
70.7k
      SET_OBJECT(data, OBJECT(x));
2105
70.7k
      IS_S4_OBJECT(x) ? SET_S4_OBJECT(data) : UNSET_S4_OBJECT(data);
2106
2107
      /* Clear the fields to drop reference counts and set the
2108
         type to LISTSXP to limit errors in case the object is
2109
         still live. */
2110
70.7k
      void ALTREP_SET_TYPEOF(SEXP, int); /* in memory.c */
2111
70.7k
      ALTREP_SET_TYPEOF(x, LISTSXP);
2112
70.7k
      SETALTREP(x, 0);
2113
70.7k
      SET_ATTRIB(x, R_NilValue);
2114
70.7k
      SETCAR(x, R_NilValue);
2115
70.7k
      SETCDR(x, R_NilValue);
2116
70.7k
      SET_TAG(x, R_NilValue);
2117
70.7k
      SET_OBJECT(x, 0);
2118
70.7k
      UNSET_S4_OBJECT(x);
2119
      /* NAMED should be zero */
2120
2121
70.7k
      return data;
2122
70.7k
  }
2123
141k
    }
2124
72.3k
    return x;
2125
143k
}
2126
2127
2128
/**
2129
 ** Initialize ALTREP Classes
2130
 **/
2131
2132
attribute_hidden void R_init_altrep(void)
2133
32
{
2134
32
    InitCompactIntegerClass();
2135
32
    InitCompactRealClass();
2136
32
    InitDefferredStringClass();
2137
32
    InitMmapIntegerClass(NULL);
2138
32
    InitMmapRealClass(NULL);
2139
32
    InitWrapIntegerClass(NULL);
2140
32
    InitWrapLogicalClass(NULL);
2141
32
    InitWrapRealClass(NULL);
2142
32
    InitWrapComplexClass(NULL);
2143
32
    InitWrapRawClass(NULL);
2144
32
    InitWrapStringClass(NULL);
2145
    InitWrapListClass(NULL);
2146
32
}