1 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 //
3 // Nullable.h: Rcpp R/C++ interface class library -- SEXP container which can be NULL
4 //
5 // Copyright (C) 2015         Dirk Eddelbuettel and Daniel C. Dillon
6 //
7 // This file is part of Rcpp.
8 //
9 // Rcpp is free software: you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Rcpp is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Rcpp.  If not, see <http://www.gnu.org/licenses/>.
21 
22 #ifndef Rcpp_Nullable_h
23 #define Rcpp_Nullable_h
24 
25 // We looked into the safe_bool_idiom [1] but found that more trouble than is
26 // warranted here.  We first and foremost want an operator SEXP() which got in
27 // the way of redefining operator bool.
28 // [1] http://www.artima.com/cppsource/safebool.html)
29 
30 namespace Rcpp {
31 
32     template<class T>
33     class Nullable {
34     public:
35 
36         /**
37          * Empty no-argument constructor of a Nullable object
38          *
39          * Assigns (R's) NULL value, and sets validator to FALSE
40          */
Nullable()41         inline Nullable() : m_sexp(R_NilValue), m_set(false) {}
42 
43         /**
44          * Template constructor of a Nullable object
45          *
46          * Assigns object, and set validator to TRUE
47          */
48 
Nullable(const T & t)49         inline Nullable(const T &t) : m_sexp(t),  m_set(true) {}
50 
51         /**
52          * Standard constructor of a Nullable object
53          *
54          * @param SEXP is stored
55          */
Nullable(SEXP t)56         inline Nullable(SEXP t) {
57             m_sexp = t;
58             m_set = true;
59         }
60 
61     public:
62 
63         /**
64          * Copy constructor for Nullable object
65          *
66          * @param SEXP is used to update internal copy
67          */
68         inline Nullable &operator=(SEXP sexp) {
69             m_sexp = sexp;
70             m_set = true;
71             return *this;
72         }
73 
74         /**
75          * operator SEXP() to return nullable object
76          *
77          * @throw 'not initialized' if object has not been set
78          */
SEXP()79         inline operator SEXP() const {
80             checkIfSet();
81             return m_sexp;
82         }
83 
84         /**
85          * get() accessor for object
86          *
87          * @throw 'not initialized' if object has not been set
88          */
get()89         inline SEXP get() const {
90             checkIfSet();
91             return m_sexp;
92         }
93 
94         /**
95          * Boolean test for usability as a T
96          */
isUsable()97         inline bool isUsable() const {
98             return m_set && !Rf_isNull(m_sexp);
99         }
100 
101         /**
102          * Boolean test for NULL
103          *
104          * @throw 'not initialized' if object has not been set
105          */
isNull()106         inline bool isNull() const {
107             checkIfSet();
108             return Rf_isNull(m_sexp);
109         }
110 
111         /**
112          * Boolean test for not NULL
113          *
114          * @throw 'not initialized' if object has not been set
115          */
isNotNull()116         inline bool isNotNull() const {
117             return ! isNull();
118         }
119 
120         /**
121          * Test function to check if object has been initialized
122          *
123          */
isSet(void)124         inline bool isSet(void) const { return m_set; }
125 
126         /**
127          * Returns m_sexp as a T
128          */
as()129         inline T as() { return get(); }
130 
131         /**
132          * Return a clone of m_sexp as a T
133          */
clone()134         inline T clone() const { return Rcpp::clone(get()); }
135 
136     private:
137         SEXP m_sexp;
138         bool m_set;
139 
checkIfSet(void)140         inline void checkIfSet(void) const {
141             if (!m_set) {
142                 throw ::Rcpp::exception("Not initialized");
143             }
144         }
145     };
146 }
147 
148 #endif
149