[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/tmastny/cpp11/master/inst/include/cpp11/external_pointer.hpp [Back]  [Original]

#pragma once

#include              // for nullptr_t, NULL
#include               // for bad_weak_ptr
#include          // for add_lvalue_reference
#include "cpp11/R.hpp"         // for SEXP, SEXPREC, TYPEOF, R_NilValue, R_C...
#include "cpp11/protect.hpp"   // for protect, safe, protect::function
#include "cpp11/r_vector.hpp"  // for type_error
#include "cpp11/sexp.hpp"      // for sexp

namespace cpp11 {

template 
void default_deleter(T* obj) {
  delete obj;
}

template 
class external_pointer {
 private:
  sexp data_ = R_NilValue;

  static SEXP valid_type(SEXP data) {
    if (TYPEOF(data) != EXTPTRSXP) {
      throw type_error(EXTPTRSXP, TYPEOF(data));
    }

    return data;
  }

  static void r_deleter(SEXP p) {
    if (TYPEOF(p) != EXTPTRSXP) return;

    T* ptr = static_cast(R_ExternalPtrAddr(p));

    if (ptr == NULL) {
      return;
    }

    R_ClearExternalPtr(p);

    Deleter(ptr);
  }

 public:
  using pointer = T*;

  external_pointer() noexcept {}
  external_pointer(std::nullptr_t) noexcept {}

  external_pointer(SEXP data) : data_(valid_type(data)) {}

  external_pointer(pointer p, bool use_deleter = true, bool finalize_on_exit = true)
      : data_(safe[R_MakeExternalPtr]((void*)p, R_NilValue, R_NilValue)) {
    if (use_deleter) {
      R_RegisterCFinalizerEx(data_, r_deleter, static_cast(finalize_on_exit));
    }
  }

  external_pointer(const external_pointer& rhs) {
    data_ = safe[Rf_shallow_duplicate](rhs.data_);
  }

  external_pointer(external_pointer&& rhs) { reset(rhs.release()); }

  external_pointer& operator=(external_pointer&& rhs) noexcept { reset(rhs.release()); }

  external_pointer& operator=(std::nullptr_t) noexcept { reset(); };

  operator SEXP() const noexcept { return data_; }

  pointer get() const noexcept {
    pointer addr = static_cast(R_ExternalPtrAddr(data_));
    if (addr == nullptr) {
      return nullptr;
    }
    return addr;
  }

  typename std::add_lvalue_reference::type operator*() {
    pointer addr = get();
    if (addr == nullptr) {
      throw std::bad_weak_ptr();
    }
    return *get();
  }

  pointer operator->() const {
    pointer addr = get();
    if (addr == nullptr) {
      throw std::bad_weak_ptr();
    }
    return get();
  }

  pointer release() noexcept {
    if (get() == nullptr) {
      return nullptr;
    }
    pointer ptr = get();
    R_ClearExternalPtr(data_);

    return ptr;
  }

  void reset(pointer ptr = pointer()) {
    SEXP old_data = data_;
    data_ = safe[R_MakeExternalPtr]((void*)ptr, R_NilValue, R_NilValue);
    r_deleter(old_data);
  }

  void swap(external_pointer& other) noexcept {
    SEXP tmp = other.data_;
    other.data_ = data_;
    data_ = tmp;
  }

  operator bool() noexcept { return data_ != nullptr; }
};

template 
void swap(external_pointer& lhs, external_pointer& rhs) noexcept {
  lhs.swap(rhs);
}

template 
bool operator==(const external_pointer& x,
                const external_pointer& y) {
  return x.data_ == y.data_;
}

template 
bool operator!=(const external_pointer& x,
                const external_pointer& y) {
  return x.data_ != y.data_;
}

template 
bool operator=(const external_pointer& x,
                const external_pointer& y) {
  return x.data_ >= y.data_;
}

}  // namespace cpp11

Web Proxy Viewer  |  New URL  |  Original Page