|
Rcpp Version 0.9.10
|
00001 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 4 -*- 00002 // 00003 // plus.h: Rcpp R/C++ interface class library -- operator+ 00004 // 00005 // Copyright (C) 2010 - 2011 Dirk Eddelbuettel and Romain Francois 00006 // 00007 // This file is part of Rcpp. 00008 // 00009 // Rcpp is free software: you can redistribute it and/or modify it 00010 // under the terms of the GNU General Public License as published by 00011 // the Free Software Foundation, either version 2 of the License, or 00012 // (at your option) any later version. 00013 // 00014 // Rcpp is distributed in the hope that it will be useful, but 00015 // WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 // GNU General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU General Public License 00020 // along with Rcpp. If not, see <http://www.gnu.org/licenses/>. 00021 00022 #ifndef Rcpp__sugar__plus_h 00023 #define Rcpp__sugar__plus_h 00024 00025 namespace Rcpp{ 00026 namespace sugar{ 00027 00028 template <int RTYPE, bool LHS_NA, typename LHS_T, bool RHS_NA, typename RHS_T > 00029 class Plus_Vector_Vector : public Rcpp::VectorBase<RTYPE, true , Plus_Vector_Vector<RTYPE,LHS_NA,LHS_T,RHS_NA,RHS_T> > { 00030 public: 00031 typedef typename traits::storage_type<RTYPE>::type STORAGE ; 00032 typedef typename Rcpp::VectorBase<RTYPE,LHS_NA,LHS_T> LHS_TYPE ; 00033 typedef typename Rcpp::VectorBase<RTYPE,RHS_NA,RHS_T> RHS_TYPE ; 00034 00035 typedef typename Rcpp::traits::Extractor< RTYPE, LHS_NA, LHS_T>::type LHS_EXT ; 00036 typedef typename Rcpp::traits::Extractor< RTYPE, RHS_NA, RHS_T>::type RHS_EXT ; 00037 00038 Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : 00039 lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} 00040 00041 inline STORAGE operator[]( int i ) const { 00042 STORAGE lhs_ = lhs[i] ; 00043 if( traits::is_na<RTYPE>(lhs_) ) return lhs_ ; 00044 STORAGE rhs_ = rhs[i] ; 00045 return traits::is_na<RTYPE>(rhs_) ? rhs_ : (lhs_ + rhs_) ; 00046 } 00047 00048 inline int size() const { return lhs.size() ; } 00049 00050 private: 00051 const LHS_EXT& lhs ; 00052 const RHS_EXT& rhs ; 00053 } ; 00054 // specialization of the above for REALSXP because : 00055 // NA_REAL + NA_REAL = NA_REAL 00056 // NA_REAL + x = NA_REAL 00057 // x + NA_REAL = NA_REAL 00058 template <bool LHS_NA, typename LHS_T, bool RHS_NA, typename RHS_T > 00059 class Plus_Vector_Vector<REALSXP,LHS_NA,LHS_T,RHS_NA,RHS_T> : 00060 public Rcpp::VectorBase<REALSXP, true , Plus_Vector_Vector<REALSXP,LHS_NA,LHS_T,RHS_NA,RHS_T> > { 00061 public: 00062 typedef typename Rcpp::VectorBase<REALSXP,LHS_NA,LHS_T> LHS_TYPE ; 00063 typedef typename Rcpp::VectorBase<REALSXP,RHS_NA,RHS_T> RHS_TYPE ; 00064 00065 typedef typename Rcpp::traits::Extractor<REALSXP, LHS_NA, LHS_T>::type LHS_EXT ; 00066 typedef typename Rcpp::traits::Extractor<REALSXP, RHS_NA, RHS_T>::type RHS_EXT ; 00067 00068 Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : 00069 lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} 00070 00071 inline double operator[]( int i ) const { 00072 return lhs[i] + rhs[i] ; 00073 } 00074 00075 inline int size() const { return lhs.size() ; } 00076 00077 private: 00078 const LHS_EXT& lhs ; 00079 const RHS_EXT& rhs ; 00080 } ; 00081 00082 00083 00084 00085 // specialization LHS_NA = false 00086 template <int RTYPE, typename LHS_T, bool RHS_NA, typename RHS_T > 00087 class Plus_Vector_Vector<RTYPE,false,LHS_T,RHS_NA,RHS_T> : public Rcpp::VectorBase<RTYPE,true, Plus_Vector_Vector<RTYPE,false,LHS_T,RHS_NA,RHS_T> > { 00088 public: 00089 typedef typename traits::storage_type<RTYPE>::type STORAGE ; 00090 typedef typename Rcpp::VectorBase<RTYPE,false,LHS_T> LHS_TYPE ; 00091 typedef typename Rcpp::VectorBase<RTYPE,RHS_NA,RHS_T> RHS_TYPE ; 00092 00093 typedef typename Rcpp::traits::Extractor< RTYPE, false, LHS_T>::type LHS_EXT ; 00094 typedef typename Rcpp::traits::Extractor< RTYPE, RHS_NA, RHS_T>::type RHS_EXT ; 00095 00096 Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : 00097 lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} 00098 00099 inline STORAGE operator[]( int i ) const { 00100 STORAGE rhs_ = rhs[i] ; 00101 if( traits::is_na<RTYPE>(rhs_) ) return rhs_ ; 00102 return lhs[i] + rhs_ ; 00103 } 00104 00105 inline int size() const { return lhs.size() ; } 00106 00107 private: 00108 const LHS_EXT& lhs ; 00109 const RHS_EXT& rhs ; 00110 } ; 00111 // LHS_NA = false & RTYPE = REALSXP 00112 template <typename LHS_T, bool RHS_NA, typename RHS_T > 00113 class Plus_Vector_Vector<REALSXP,false,LHS_T,RHS_NA,RHS_T> : 00114 public Rcpp::VectorBase<REALSXP,true, Plus_Vector_Vector<REALSXP,false,LHS_T,RHS_NA,RHS_T> > { 00115 public: 00116 typedef typename Rcpp::VectorBase<REALSXP,false,LHS_T> LHS_TYPE ; 00117 typedef typename Rcpp::VectorBase<REALSXP,RHS_NA,RHS_T> RHS_TYPE ; 00118 00119 typedef typename Rcpp::traits::Extractor<REALSXP, false, LHS_T>::type LHS_EXT ; 00120 typedef typename Rcpp::traits::Extractor<REALSXP, RHS_NA, RHS_T>::type RHS_EXT ; 00121 00122 Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : 00123 lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} 00124 00125 inline double operator[]( int i ) const { 00126 return lhs[i] + rhs[i] ; 00127 } 00128 00129 inline int size() const { return lhs.size() ; } 00130 00131 private: 00132 const LHS_EXT& lhs ; 00133 const RHS_EXT& rhs ; 00134 } ; 00135 00136 00137 00138 // specialization for RHS_NA = false 00139 template <int RTYPE, bool LHS_NA, typename LHS_T, typename RHS_T > 00140 class Plus_Vector_Vector<RTYPE,LHS_NA,LHS_T,false,RHS_T> : public Rcpp::VectorBase<RTYPE, true , Plus_Vector_Vector<RTYPE,LHS_NA,LHS_T,false,RHS_T> > { 00141 public: 00142 typedef typename traits::storage_type<RTYPE>::type STORAGE ; 00143 typedef typename Rcpp::VectorBase<RTYPE,LHS_NA,LHS_T> LHS_TYPE ; 00144 typedef typename Rcpp::VectorBase<RTYPE,false,RHS_T> RHS_TYPE ; 00145 00146 typedef typename Rcpp::traits::Extractor< RTYPE, LHS_NA, LHS_T>::type LHS_EXT ; 00147 typedef typename Rcpp::traits::Extractor< RTYPE, false, RHS_T>::type RHS_EXT ; 00148 00149 Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : 00150 lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} 00151 00152 inline STORAGE operator[]( int i ) const { 00153 STORAGE lhs_ = lhs[i] ; 00154 if( traits::is_na<RTYPE>(lhs_) ) return lhs_ ; 00155 return lhs_ + rhs[i] ; 00156 } 00157 00158 inline int size() const { return lhs.size() ; } 00159 00160 private: 00161 const LHS_EXT& lhs ; 00162 const RHS_EXT& rhs ; 00163 } ; 00164 // RHS_NA = false, RTYPE = REALSXP 00165 template <bool LHS_NA, typename LHS_T, typename RHS_T > 00166 class Plus_Vector_Vector<REALSXP,LHS_NA,LHS_T,false,RHS_T> : 00167 public Rcpp::VectorBase<REALSXP, true , Plus_Vector_Vector<REALSXP,LHS_NA,LHS_T,false,RHS_T> > { 00168 public: 00169 typedef typename Rcpp::VectorBase<REALSXP,LHS_NA,LHS_T> LHS_TYPE ; 00170 typedef typename Rcpp::VectorBase<REALSXP,false,RHS_T> RHS_TYPE ; 00171 00172 typedef typename Rcpp::traits::Extractor<REALSXP, LHS_NA, LHS_T>::type LHS_EXT ; 00173 typedef typename Rcpp::traits::Extractor<REALSXP, false, RHS_T>::type RHS_EXT ; 00174 00175 Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : 00176 lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} 00177 00178 inline double operator[]( int i ) const { 00179 return lhs[i] + rhs[i] ; 00180 } 00181 00182 inline int size() const { return lhs.size() ; } 00183 00184 private: 00185 const LHS_EXT& lhs ; 00186 const RHS_EXT& rhs ; 00187 } ; 00188 00189 00190 00191 00192 // specialization for RHS_NA = false and LHS_NA = false 00193 template <int RTYPE, typename LHS_T, typename RHS_T > 00194 class Plus_Vector_Vector<RTYPE,false,LHS_T,false,RHS_T> : public Rcpp::VectorBase<RTYPE, false , Plus_Vector_Vector<RTYPE,false,LHS_T,false,RHS_T> > { 00195 public: 00196 typedef typename traits::storage_type<RTYPE>::type STORAGE ; 00197 typedef typename Rcpp::VectorBase<RTYPE,false,LHS_T> LHS_TYPE ; 00198 typedef typename Rcpp::VectorBase<RTYPE,false,RHS_T> RHS_TYPE ; 00199 00200 typedef typename Rcpp::traits::Extractor< RTYPE, false, LHS_T>::type LHS_EXT ; 00201 typedef typename Rcpp::traits::Extractor< RTYPE, false, RHS_T>::type RHS_EXT ; 00202 00203 Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : 00204 lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} 00205 00206 inline STORAGE operator[]( int i ) const { 00207 return lhs[i] + rhs[i] ; 00208 } 00209 00210 inline int size() const { return lhs.size() ; } 00211 00212 private: 00213 const LHS_EXT& lhs ; 00214 const RHS_EXT& rhs ; 00215 } ; 00216 // specialization for RHS_NA = false and LHS_NA = false, RTYPE = REALSXP 00217 template <typename LHS_T, typename RHS_T > 00218 class Plus_Vector_Vector<REALSXP,false,LHS_T,false,RHS_T> : 00219 public Rcpp::VectorBase<REALSXP, false , Plus_Vector_Vector<REALSXP,false,LHS_T,false,RHS_T> > { 00220 public: 00221 typedef typename Rcpp::VectorBase<REALSXP,false,LHS_T> LHS_TYPE ; 00222 typedef typename Rcpp::VectorBase<REALSXP,false,RHS_T> RHS_TYPE ; 00223 00224 typedef typename Rcpp::traits::Extractor<REALSXP, false, LHS_T>::type LHS_EXT ; 00225 typedef typename Rcpp::traits::Extractor<REALSXP, false, RHS_T>::type RHS_EXT ; 00226 00227 Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : 00228 lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} 00229 00230 inline double operator[]( int i ) const { 00231 return lhs[i] + rhs[i] ; 00232 } 00233 00234 inline int size() const { return lhs.size() ; } 00235 00236 private: 00237 const LHS_EXT& lhs ; 00238 const RHS_EXT& rhs ; 00239 } ; 00240 00241 00242 00243 00244 00245 00246 00247 template <int RTYPE, bool NA, typename T> 00248 class Plus_Vector_Primitive : 00249 public Rcpp::VectorBase<RTYPE,true, Plus_Vector_Primitive<RTYPE,NA,T> > { 00250 public: 00251 typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ; 00252 typedef typename traits::storage_type<RTYPE>::type STORAGE ; 00253 00254 typedef typename Rcpp::traits::Extractor< RTYPE, NA, T>::type EXT ; 00255 00256 Plus_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : 00257 lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na<RTYPE>(rhs_) ) 00258 {} 00259 00260 inline STORAGE operator[]( int i ) const { 00261 if( rhs_na ) return rhs ; 00262 STORAGE x = lhs[i] ; 00263 return Rcpp::traits::is_na<RTYPE>(x) ? x : (x + rhs) ; 00264 } 00265 00266 inline int size() const { return lhs.size() ; } 00267 00268 private: 00269 const EXT& lhs ; 00270 STORAGE rhs ; 00271 bool rhs_na ; 00272 00273 } ; 00274 // RTYPE = REALSXP 00275 template <bool NA, typename T> 00276 class Plus_Vector_Primitive<REALSXP,NA,T> : 00277 public Rcpp::VectorBase<REALSXP,true, Plus_Vector_Primitive<REALSXP,NA,T> > { 00278 public: 00279 typedef typename Rcpp::VectorBase<REALSXP,NA,T> VEC_TYPE ; 00280 typedef typename Rcpp::traits::Extractor< REALSXP, NA, T>::type EXT ; 00281 00282 Plus_Vector_Primitive( const VEC_TYPE& lhs_, double rhs_ ) : 00283 lhs(lhs_.get_ref()), rhs(rhs_) 00284 {} 00285 00286 inline double operator[]( int i ) const { 00287 return rhs + lhs[i] ; 00288 } 00289 00290 inline int size() const { return lhs.size() ; } 00291 00292 private: 00293 const EXT& lhs ; 00294 double rhs ; 00295 } ; 00296 00297 00298 00299 template <int RTYPE, typename T> 00300 class Plus_Vector_Primitive<RTYPE,false,T> : public Rcpp::VectorBase<RTYPE,false, Plus_Vector_Primitive<RTYPE,false,T> > { 00301 public: 00302 typedef typename Rcpp::VectorBase<RTYPE,false,T> VEC_TYPE ; 00303 typedef typename traits::storage_type<RTYPE>::type STORAGE ; 00304 00305 typedef typename Rcpp::traits::Extractor< RTYPE, false, T>::type EXT ; 00306 00307 Plus_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : 00308 lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na<RTYPE>(rhs_) ) {} 00309 00310 inline STORAGE operator[]( int i ) const { 00311 return rhs_na ? rhs : (rhs + lhs[i] ) ; 00312 } 00313 00314 inline int size() const { return lhs.size() ; } 00315 00316 private: 00317 const EXT& lhs ; 00318 STORAGE rhs ; 00319 bool rhs_na ; 00320 } ; 00321 // RTYPE = REALSXP 00322 template <typename T> 00323 class Plus_Vector_Primitive<REALSXP,false,T> : 00324 public Rcpp::VectorBase<REALSXP,false, Plus_Vector_Primitive<REALSXP,false,T> > { 00325 public: 00326 typedef typename Rcpp::VectorBase<REALSXP,false,T> VEC_TYPE ; 00327 00328 typedef typename Rcpp::traits::Extractor< REALSXP, false, T>::type EXT ; 00329 00330 Plus_Vector_Primitive( const VEC_TYPE& lhs_, double rhs_ ) : 00331 lhs(lhs_.get_ref()), rhs(rhs_) {} 00332 00333 inline double operator[]( int i ) const { 00334 return rhs + lhs[i] ; 00335 } 00336 00337 inline int size() const { return lhs.size() ; } 00338 00339 private: 00340 const EXT& lhs ; 00341 double rhs ; 00342 } ; 00343 00344 00345 00346 00347 00348 00349 // Vector * nona(primitive) 00350 template <int RTYPE, bool NA, typename T> 00351 class Plus_Vector_Primitive_nona : public Rcpp::VectorBase<RTYPE,true, Plus_Vector_Primitive_nona<RTYPE,NA,T> > { 00352 public: 00353 typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ; 00354 typedef typename traits::storage_type<RTYPE>::type STORAGE ; 00355 typedef typename Rcpp::traits::Extractor< RTYPE, NA, T>::type EXT ; 00356 00357 Plus_Vector_Primitive_nona( const VEC_TYPE& lhs_, STORAGE rhs_ ) : 00358 lhs(lhs_.get_ref()), rhs(rhs_) 00359 {} 00360 00361 inline STORAGE operator[]( int i ) const { 00362 STORAGE x = lhs[i] ; 00363 return Rcpp::traits::is_na<RTYPE>(x) ? x : (x + rhs) ; 00364 } 00365 00366 inline int size() const { return lhs.size() ; } 00367 00368 private: 00369 const EXT& lhs ; 00370 STORAGE rhs ; 00371 00372 } ; 00373 template <bool NA, typename T> 00374 class Plus_Vector_Primitive_nona<REALSXP,NA,T> : 00375 public Rcpp::VectorBase<REALSXP,true, Plus_Vector_Primitive_nona<REALSXP,NA,T> > { 00376 public: 00377 typedef typename Rcpp::VectorBase<REALSXP,NA,T> VEC_TYPE ; 00378 typedef typename Rcpp::traits::Extractor<REALSXP, NA, T>::type EXT ; 00379 00380 Plus_Vector_Primitive_nona( const VEC_TYPE& lhs_, double rhs_ ) : 00381 lhs(lhs_.get_ref()), rhs(rhs_) 00382 {} 00383 00384 inline double operator[]( int i ) const { 00385 return rhs + lhs[i] ; 00386 } 00387 00388 inline int size() const { return lhs.size() ; } 00389 00390 private: 00391 const EXT& lhs ; 00392 double rhs ; 00393 00394 } ; 00395 00396 00397 00398 template <int RTYPE, typename T> 00399 class Plus_Vector_Primitive_nona<RTYPE,false,T> : public Rcpp::VectorBase<RTYPE,false, Plus_Vector_Primitive_nona<RTYPE,false,T> > { 00400 public: 00401 typedef typename Rcpp::VectorBase<RTYPE,false,T> VEC_TYPE ; 00402 typedef typename traits::storage_type<RTYPE>::type STORAGE ; 00403 00404 typedef typename Rcpp::traits::Extractor< RTYPE, false, T>::type EXT ; 00405 00406 Plus_Vector_Primitive_nona( const VEC_TYPE& lhs_, STORAGE rhs_ ) : 00407 lhs(lhs_.get_ref()), rhs(rhs_) {} 00408 00409 inline STORAGE operator[]( int i ) const { 00410 return rhs + lhs[i] ; 00411 } 00412 00413 inline int size() const { return lhs.size() ; } 00414 00415 private: 00416 const EXT& lhs ; 00417 STORAGE rhs ; 00418 00419 } ; 00420 // RTYPE = REALSXP 00421 template <typename T> 00422 class Plus_Vector_Primitive_nona<REALSXP,false,T> : 00423 public Rcpp::VectorBase<REALSXP,false, Plus_Vector_Primitive_nona<REALSXP,false,T> > { 00424 public: 00425 typedef typename Rcpp::VectorBase<REALSXP,false,T> VEC_TYPE ; 00426 typedef typename Rcpp::traits::Extractor< REALSXP, false, T>::type EXT ; 00427 00428 Plus_Vector_Primitive_nona( const VEC_TYPE& lhs_, double rhs_ ) : 00429 lhs(lhs_.get_ref()), rhs(rhs_) {} 00430 00431 inline double operator[]( int i ) const { 00432 return rhs + lhs[i] ; 00433 } 00434 00435 inline int size() const { return lhs.size() ; } 00436 00437 private: 00438 const EXT& lhs ; 00439 double rhs ; 00440 00441 } ; 00442 00443 } 00444 } 00445 00446 template <int RTYPE,bool NA, typename T> 00447 inline Rcpp::sugar::Plus_Vector_Primitive<RTYPE,NA,T> 00448 operator+( 00449 const Rcpp::VectorBase<RTYPE,NA,T>& lhs, 00450 typename Rcpp::traits::storage_type<RTYPE>::type rhs 00451 ) { 00452 return Rcpp::sugar::Plus_Vector_Primitive<RTYPE,NA,T>( lhs, rhs ) ; 00453 } 00454 00455 00456 template <int RTYPE,bool NA, typename T> 00457 inline Rcpp::sugar::Plus_Vector_Primitive< RTYPE , NA , T > 00458 operator+( 00459 typename Rcpp::traits::storage_type<RTYPE>::type rhs, 00460 const Rcpp::VectorBase<RTYPE,NA,T>& lhs 00461 ) { 00462 return Rcpp::sugar::Plus_Vector_Primitive<RTYPE,NA, T >( lhs, rhs ) ; 00463 } 00464 00465 00466 00467 template <int RTYPE,bool NA, typename T> 00468 inline Rcpp::sugar::Plus_Vector_Primitive_nona<RTYPE,NA,T> 00469 operator+( 00470 const Rcpp::VectorBase<RTYPE,NA,T>& lhs, 00471 typename Rcpp::sugar::NonaPrimitive< typename Rcpp::traits::storage_type<RTYPE>::type > rhs 00472 ) { 00473 return Rcpp::sugar::Plus_Vector_Primitive_nona<RTYPE,NA,T>( lhs, rhs ) ; 00474 } 00475 00476 template <int RTYPE,bool NA, typename T> 00477 inline Rcpp::sugar::Plus_Vector_Primitive_nona< RTYPE , NA , T > 00478 operator+( 00479 typename Rcpp::sugar::NonaPrimitive< typename Rcpp::traits::storage_type<RTYPE>::type > rhs, 00480 const Rcpp::VectorBase<RTYPE,NA,T>& lhs 00481 ) { 00482 return Rcpp::sugar::Plus_Vector_Primitive_nona<RTYPE,NA, T >( lhs, rhs ) ; 00483 } 00484 00485 00486 template <int RTYPE,bool LHS_NA, typename LHS_T, bool RHS_NA, typename RHS_T> 00487 inline Rcpp::sugar::Plus_Vector_Vector< 00488 RTYPE , 00489 LHS_NA, LHS_T, 00490 RHS_NA, RHS_T 00491 > 00492 operator+( 00493 const Rcpp::VectorBase<RTYPE,LHS_NA,LHS_T>& lhs, 00494 const Rcpp::VectorBase<RTYPE,RHS_NA,RHS_T>& rhs 00495 ) { 00496 return Rcpp::sugar::Plus_Vector_Vector< 00497 RTYPE, 00498 LHS_NA, LHS_T, 00499 RHS_NA, RHS_T 00500 >( lhs, rhs ) ; 00501 } 00502 00503 #endif