File: XPtr.h

package info (click to toggle)
rcpp 0.12.9-1
  • links: PTS
  • area: main
  • in suites: stretch
  • size: 10,776 kB
  • ctags: 17,733
  • sloc: ansic: 43,728; cpp: 39,001; sh: 21; makefile: 1
file content (186 lines) | stat: -rw-r--r-- 5,995 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*-
//
// XPtr.h: Rcpp R/C++ interface class library -- smart external pointers
//
// Copyright (C) 2009 - 2013	Dirk Eddelbuettel and Romain Francois
//
// This file is part of Rcpp.
//
// Rcpp is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Rcpp is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Rcpp.  If not, see <http://www.gnu.org/licenses/>.

#ifndef Rcpp_XPtr_h
#define Rcpp_XPtr_h

#include <RcppCommon.h>

namespace Rcpp{

template <typename T>
void standard_delete_finalizer(T* obj){
    delete obj ;
}

template <typename T, void Finalizer(T*) >
void finalizer_wrapper(SEXP p){
    if( TYPEOF(p) == EXTPTRSXP ){
        T* ptr = (T*) R_ExternalPtrAddr(p) ;
        RCPP_DEBUG_3( "finalizer_wrapper<%s>(SEXP p = <%p>). ptr = %p", DEMANGLE(T), p, ptr  )
        Finalizer(ptr) ;
    }
}

template <
    typename T,
    template <class> class StoragePolicy = PreserveStorage,
    void Finalizer(T*) = standard_delete_finalizer<T>
>
class XPtr :
    public StoragePolicy< XPtr<T,StoragePolicy, Finalizer> >,
    public SlotProxyPolicy< XPtr<T,StoragePolicy, Finalizer> >,
    public AttributeProxyPolicy< XPtr<T,StoragePolicy, Finalizer> >,
    public TagProxyPolicy< XPtr<T,StoragePolicy, Finalizer> >,
    public ProtectedProxyPolicy< XPtr<T,StoragePolicy, Finalizer> >,
    public RObjectMethods< XPtr<T,StoragePolicy, Finalizer> >
{
public:

    typedef StoragePolicy<XPtr> Storage ;

    /**
     * constructs a XPtr wrapping the external pointer (EXTPTRSXP SEXP)
     *
     * @param xp external pointer to wrap
     */
    explicit XPtr(SEXP x, SEXP tag = R_NilValue, SEXP prot = R_NilValue) {
        if( TYPEOF(x) != EXTPTRSXP )
            throw ::Rcpp::not_compatible( "expecting an external pointer" ) ;
        Storage::set__(x) ;
        R_SetExternalPtrTag( x, tag ) ;
        R_SetExternalPtrProtected( x, prot ) ;
    } ;

    /**
     * creates a new external pointer wrapping the dumb pointer p.
     *
     * @param p dumb pointer to some object
     * @param set_delete_finalizer if set to true, a finalizer will
     *        be registered for the external pointer. The finalizer
     *        is called when the xp is garbage collected. The finalizer
     *        is merely a call to the delete operator or the pointer
     *        so you need to make sure the pointer can be "delete" d
     *        this way (has to be a C++ object)
     */
    explicit XPtr(T* p, bool set_delete_finalizer = true, SEXP tag = R_NilValue, SEXP prot = R_NilValue){
        RCPP_DEBUG_2( "XPtr(T* p = <%p>, bool set_delete_finalizer = %s, SEXP tag = R_NilValue, SEXP prot = R_NilValue)", p, ( set_delete_finalizer ? "true" : "false" ) )
        Storage::set__( R_MakeExternalPtr( (void*)p , tag, prot) ) ;
        if( set_delete_finalizer ){
            setDeleteFinalizer() ;
        }
    }

    XPtr( const XPtr& other ) {
        Storage::copy__(other) ;
    }

    XPtr& operator=(const XPtr& other){
    	    Storage::copy__(other) ;
    	    return *this ;
    }

    /**
     * Typesafe accessor for underlying pointer (use checked_get
     * if you want an exception thrown if the pointer is NULL)
     */
    inline T* get() const {
        return (T*)(R_ExternalPtrAddr( Storage::get__() ));
    }

    /**
     * Boolean operator wrapper for get() using the "safe bool idiom", see:
     * http://www.boost.org/doc/libs/1_57_0/boost/smart_ptr/detail/operator_bool.hpp
     */
    typedef void (*unspecified_bool_type)();
    static void unspecified_bool_true() {}
    operator unspecified_bool_type() const
    {
        return get() == NULL ? 0 : unspecified_bool_true;
    }
    bool operator!() const
    {
        return get() == NULL;
    }

    /**
     * Access underlying pointer throwing an exception if the ptr is NULL
     */
    inline T* checked_get() const {
        T* ptr = get();
        if (ptr == NULL)
            throw ::Rcpp::exception("external pointer is not valid" ) ;
        return ptr;
    }

    /**
     * Returns a reference to the object wrapped. This allows this
     * object to look and feel like a dumb pointer to T
     */
    T& operator*() const {
        return *(checked_get()) ;
    }

    /**
     * Returns the dumb pointer. This allows to call the -> operator
     * on this as if it was the dumb pointer
     */
    T* operator->() const {
        return checked_get() ;
    }

    void setDeleteFinalizer() {
        R_RegisterCFinalizerEx( Storage::get__(), finalizer_wrapper<T,Finalizer> , FALSE) ;
    }

    /**
     * Release the external pointer (if any) immediately. This will cause
     * the pointer to be deleted and it's storage to be set to NULL.
     * After this call the get() method returns NULL and the checked_get()
     * method throws an exception.
     *
     * See the discussion here for the basic logic behind release:
     * https://stat.ethz.ch/pipermail/r-help/2007-August/137871.html
     */
    void release() {

        if (get() != NULL)
        {
            // Call the finalizer -- note that this implies that finalizers
            // need to be ready for a NULL external pointer value (our
            // default C++ finalizer is since delete NULL is a no-op).
            finalizer_wrapper<T,Finalizer>( Storage::get__() );

            // Clear the external pointer
            R_ClearExternalPtr( Storage::get__() );
        }
    }

    inline operator T*(){
        return checked_get() ;
    }

    void update(SEXP){}
};

} // namespace Rcpp

#endif