@@ -325,4 +325,47 @@ context("r_vector-C++") {
325
325
expect_true (x.data () != R_NilValue);
326
326
expect_true (x.size () == 3 );
327
327
}
328
+
329
+ test_that (
330
+ " writable vector truncation resizes names and retains attributes (but not dim or "
331
+ " dim names)" ) {
332
+ cpp11::writable::integers x (2 );
333
+ x[0 ] = 1 ;
334
+ x[1 ] = 2 ;
335
+
336
+ // Doubles the capacity from 2 to 4, meaning the underlying SEXP has length 4 now.
337
+ x.push_back (3 );
338
+ expect_true (Rf_xlength (x.data ()) == 4 );
339
+
340
+ // Set some names
341
+ SEXP names = PROTECT (Rf_allocVector (STRSXP, 3 ));
342
+ SET_STRING_ELT (names, 0 , Rf_mkCharCE (" x" , CE_UTF8));
343
+ SET_STRING_ELT (names, 1 , Rf_mkCharCE (" y" , CE_UTF8));
344
+ SET_STRING_ELT (names, 2 , Rf_mkCharCE (" z" , CE_UTF8));
345
+ x.names () = names;
346
+
347
+ // Length of names SEXP is actually 4 now, extended by `setAttrib()` to match
348
+ // the internal capacity
349
+ expect_true (Rf_xlength (Rf_getAttrib (x.data (), R_NamesSymbol)) == 4 );
350
+
351
+ // Set an attribute
352
+ SEXP bar = PROTECT (Rf_ScalarInteger (1 ));
353
+ x.attr (" foo" ) = bar;
354
+
355
+ // Extract out the underlying SEXP using the operator:
356
+ // - This truncates to size 3
357
+ // - This truncates and keeps names
358
+ // - This copies over attributes like `"foo"`
359
+ // - This updates the internal SEXP in `x` to the one in `x_sexp` (gross but users
360
+ // probably expect this at this point)
361
+ SEXP x_sexp = x;
362
+
363
+ expect_true (Rf_xlength (x_sexp) == 3 );
364
+ expect_true (Rf_xlength (Rf_getAttrib (x_sexp, R_NamesSymbol)) == 3 );
365
+ expect_true (Rf_getAttrib (x_sexp, Rf_install (" foo" )) == bar);
366
+
367
+ expect_true (x.data () == x_sexp);
368
+
369
+ UNPROTECT (2 );
370
+ }
328
371
}
0 commit comments