Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Take control over resizing to enforce required invariants #383

Merged
merged 3 commits into from
Aug 20, 2024

Conversation

DavisVaughan
Copy link
Member

Closes #369

@DavisVaughan DavisVaughan force-pushed the feature/keep-attributes branch from b10cbe9 to 48f3f47 Compare August 20, 2024 17:25
Comment on lines +40 to +44
template <>
inline typename r_vector<double>::underlying_type const* r_vector<double>::get_const_p(
bool is_altrep, SEXP data) {
return REAL_OR_NULL(data);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using utilities like REAL_OR_NULL() gives ALTREP types that can cheaply return a const pointer to an underlying buffer a chance to do so (like ALTREP views)

Comment on lines -762 to +788
inline r_vector<T>::r_vector(const r_vector& rhs)
: cpp11::r_vector<T>(safe[Rf_shallow_duplicate](rhs)), capacity_(rhs.capacity_) {}
inline r_vector<T>::r_vector(const r_vector& rhs) {
// We don't want to just pass through to the read-only constructor because we'd
// have to convert to `SEXP` first, which could truncate, and then we'd still have
// to shallow duplicate after that to ensure we have a duplicate, which can result in
// too many copies (#369).
//
// Instead we take control of setting all fields to try and only duplicate 1 time.
// We try and reclaim unused capacity during the duplication by only reserving up to
// the `rhs.length_`. This is nice because if the user returns this object, the
// truncation has already been done and they don't have to pay for another allocation.
// Importantly, `reserve_data()` always duplicates even if there wasn't extra capacity,
// which ensures we have our own copy.
data_ = reserve_data(rhs.data_, rhs.is_altrep_, rhs.length_);
protect_ = detail::store::insert(data_);
is_altrep_ = ALTREP(data_);
data_p_ = get_p(is_altrep_, data_);
length_ = rhs.length_;
capacity_ = rhs.length_;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This avoids the double copy from #369

Before

> profmem::profmem(test_())
Rprofmem memory profiling of:
test_()

Memory allocations:
       what   bytes              calls
1     alloc  400048 test_() -> .Call()
2     alloc  800048 test_() -> .Call()
3     alloc  400056 test_() -> .Call()
4     alloc  400056 test_() -> .Call() # <- this one is extra
total       2000208   

After

> profmem::profmem(test_())
Rprofmem memory profiling of:
test_()

Memory allocations:
       what   bytes              calls
1     alloc  400048 test_() -> .Call()
2     alloc  800048 test_() -> .Call()
3     alloc  400056 test_() -> .Call()
total       1600152  

Comment on lines +1277 to +1285
// Compared to `Rf_xlengthgets()`:
// - This always allocates, even if it is the same size, which is important when we use
// it in a constructor and need to ensure that it duplicates on the way in.
// - This copies over attributes with `Rf_copyMostAttrib()`, which is important when we
// use it in constructors and when we truncate right before returning from the `SEXP`
// operator.
// - This is more friendly to ALTREP `x`.
template <typename T>
inline SEXP r_vector<T>::reserve_data(SEXP x, bool is_altrep, R_xlen_t size) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important invariants of reserve_data() vs Rf_xlengthgets()

Useful for both:

  • Usage in constructors, when we need to enforce a duplication to occur
  • Usage during truncation, when we need to copy attributes too

@DavisVaughan DavisVaughan merged commit acca2d2 into r-lib:main Aug 20, 2024
16 checks passed
@DavisVaughan DavisVaughan deleted the feature/keep-attributes branch August 20, 2024 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Copy constructor for writable vectors is duplicating the SEXP too many times
1 participant