Skip to content

Commit 9d4878c

Browse files
committed
Unit tests and reshuffling for NA, NaN handling in Rcpp
1 parent 8a60ab7 commit 9d4878c

File tree

15 files changed

+267
-64
lines changed

15 files changed

+267
-64
lines changed

inst/include/Rcpp/hash/IndexHash.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ namespace Rcpp{
160160
}
161161

162162
inline bool not_equal(const STORAGE& lhs, const STORAGE& rhs) {
163-
return ! NAEquals<STORAGE>()(lhs, rhs);
163+
return ! internal::NAEquals<STORAGE>()(lhs, rhs);
164164
}
165165

166166
bool add_value(int i){
@@ -213,8 +213,8 @@ namespace Rcpp{
213213
union dint_u val_u;
214214
/* double is a bit tricky - we nave to normalize 0.0, NA and NaN */
215215
if (val == 0.0) val = 0.0;
216-
if (Rcpp_IsNA(val)) val = NA_REAL;
217-
else if (Rcpp_IsNaN(val)) val = R_NaN;
216+
if (internal::Rcpp_IsNA(val)) val = NA_REAL;
217+
else if (internal::Rcpp_IsNaN(val)) val = R_NaN;
218218
val_u.d = val;
219219
addr = RCPP_HASH(val_u.u[0] + val_u.u[1]);
220220
return addr ;

inst/include/Rcpp/hash/SelfHash.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ namespace sugar{
104104
union dint_u val_u;
105105
/* double is a bit tricky - we nave to normalize 0.0, NA and NaN */
106106
if (val == 0.0) val = 0.0;
107-
if (Rcpp_IsNA(val)) val = NA_REAL;
108-
else if (Rcpp_IsNaN(val)) val = R_NaN;
107+
if (internal::Rcpp_IsNA(val)) val = NA_REAL;
108+
else if (internal::Rcpp_IsNaN(val)) val = R_NaN;
109109
val_u.d = val;
110110
addr = RCPP_HASH(val_u.u[0] + val_u.u[1]);
111111
return addr ;

inst/include/Rcpp/NAComparator.h renamed to inst/include/Rcpp/internal/NAComparator.h

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,18 @@
2020
// You should have received a copy of the GNU General Public License
2121
// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
2222

23-
#ifndef Rcpp__NAComparator__h
24-
#define Rcpp__NAComparator__h
23+
#ifndef Rcpp__internal__NAComparator__h
24+
#define Rcpp__internal__NAComparator__h
2525

2626
namespace Rcpp{
27-
28-
inline bool Rcpp_IsNA(double x) {
29-
return memcmp(
30-
(void*) &x,
31-
(void*) &NA_REAL,
32-
sizeof(double)
33-
) == 0;
34-
}
35-
36-
inline bool Rcpp_IsNaN(double x) {
37-
return R_IsNaN(x);
38-
}
39-
27+
28+
namespace internal {
29+
4030
inline int StrCmp(SEXP x, SEXP y) {
41-
if (x == NA_STRING) return (y == NA_STRING ? 0 : 1);
42-
if (y == NA_STRING) return -1;
43-
if (x == y) return 0; // same string in cache
44-
return strcmp(char_nocheck(x), char_nocheck(y));
31+
if (x == NA_STRING) return (y == NA_STRING ? 0 : 1);
32+
if (y == NA_STRING) return -1;
33+
if (x == y) return 0; // same string in cache
34+
return strcmp(char_nocheck(x), char_nocheck(y));
4535
}
4636

4737
template <typename T>
@@ -88,6 +78,8 @@ struct NAComparator<SEXP> {
8878
}
8979
};
9080

81+
}
82+
9183
}
9284

9385
#endif

inst/include/Rcpp/NAEquals.h renamed to inst/include/Rcpp/internal/NAEquals.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// NAEquals.h: Rcpp R/C++ interface class library -- for allowing NA == NA
22
//
3-
// Copyright (C) 2014 Kevin UShey
3+
// Copyright (C) 2014 Kevin Ushey
44
//
55
// This file is part of Rcpp.
66
//
@@ -17,18 +17,21 @@
1717
// You should have received a copy of the GNU General Public License
1818
// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
1919

20-
#ifndef Rcpp__NAEquals__h
21-
#define Rcpp__NAEquals__h
20+
#ifndef Rcpp__internal__NAEquals__h
21+
#define Rcpp__internal__NAEquals__h
2222

2323
namespace Rcpp {
2424

25+
namespace internal {
26+
2527
template <typename T>
2628
struct NAEquals {
2729
inline bool operator()(T left, T right) const {
2830
return left == right;
2931
}
3032
};
3133

34+
// TODO: check different kinds of NA, NaNs
3235
template <>
3336
struct NAEquals<double> {
3437
inline bool operator()(double left, double right) const {
@@ -38,4 +41,6 @@ struct NAEquals<double> {
3841

3942
}
4043

44+
}
45+
4146
#endif

inst/include/Rcpp/internal/na.h

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*-
2+
/* :tabSize=4:indentSize=4:noTabs=false:folding=explicit:collapseFolds=1: */
3+
//
4+
// na.h: Rcpp R/C++ interface class library -- optimized na checking
5+
//
6+
// Copyright (C) 2012-2014 Dirk Eddelbuettel, Romain Francois and Kevin Ushey
7+
//
8+
// This file is part of Rcpp.
9+
//
10+
// Rcpp is free software: you can redistribute it and/or modify it
11+
// under the terms of the GNU General Public License as published by
12+
// the Free Software Foundation, either version 2 of the License, or
13+
// (at your option) any later version.
14+
//
15+
// Rcpp is distributed in the hope that it will be useful, but
16+
// WITHOUT ANY WARRANTY; without even the implied warranty of
17+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
// GNU General Public License for more details.
19+
//
20+
// You should have received a copy of the GNU General Public License
21+
// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
22+
23+
namespace Rcpp {
24+
namespace internal {
25+
26+
// On 64bit processors, NAs can change
27+
// we can still get a performance benefit by checking for specific
28+
// bit patterns, though
29+
30+
// we rely on the presence of unsigned long long types (could do it with
31+
// a union, but that's messier; this is cleaner)
32+
#ifdef RCPP_HAS_LONG_LONG_TYPES
33+
34+
#ifdef HAS_STATIC_ASSERT
35+
static_assert(
36+
sizeof(rcpp_ulong_long_type) == sizeof(double),
37+
"unsigned long long and double have same size"
38+
);
39+
#endif
40+
41+
static const rcpp_ulong_long_type SmallNA = 0x7FF00000000007A2;
42+
static const rcpp_ulong_long_type LargeNA = 0x7FF80000000007A2;
43+
44+
struct NACanChange {
45+
enum { value = sizeof(void*) == 8 };
46+
};
47+
48+
template <bool NACanChange>
49+
bool Rcpp_IsNA__impl(double);
50+
51+
template <>
52+
inline bool Rcpp_IsNA__impl<true>(double x) {
53+
return memcmp(
54+
(void*) &x,
55+
(void*) &SmallNA,
56+
sizeof(double)
57+
) == 0 or memcmp(
58+
(void*) &x,
59+
(void*) &LargeNA,
60+
sizeof(double)
61+
) == 0;
62+
}
63+
64+
template <>
65+
inline bool Rcpp_IsNA__impl<false>(double x) {
66+
printf("false\n");
67+
return memcmp(
68+
(void*) &x,
69+
(void*) &LargeNA,
70+
sizeof(double)
71+
) == 0;
72+
}
73+
74+
inline bool Rcpp_IsNA(double x) {
75+
return Rcpp_IsNA__impl< NACanChange::value >(x);
76+
}
77+
78+
inline bool Rcpp_IsNaN(double x) {
79+
return R_IsNaN(x);
80+
}
81+
82+
#else
83+
84+
// fallback when we don't have unsigned long long
85+
86+
inline bool Rcpp_IsNA(double x) {
87+
return R_IsNA(x);
88+
}
89+
90+
inline bool Rcpp_IsNaN(double x) {
91+
return R_IsNaN(x);
92+
}
93+
94+
#endif
95+
96+
}
97+
}

inst/include/Rcpp/longlong.h

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,37 +26,16 @@
2626
// forbidden by CRAN which stick with the C++98 standard predating it.
2727
// One way to get 'long long' is to switch to C++11, another is to use
2828
// clang++ from the llvm project.
29-
3029
#ifdef __GNUC__
31-
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined (__clang__) && defined(__LP64__))
32-
33-
#if defined(__GNUC__) && defined(__LONG_LONG_MAX__)
34-
__extension__ typedef long long int rcpp_long_long_type;
35-
__extension__ typedef unsigned long long int rcpp_ulong_long_type;
36-
#define RCPP_HAS_LONG_LONG_TYPES
37-
#endif
30+
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined (__clang__) && defined(__LP64__))
3831

39-
#endif
32+
#if defined(__GNUC__) && defined(__LONG_LONG_MAX__)
33+
__extension__ typedef long long int rcpp_long_long_type;
34+
__extension__ typedef unsigned long long int rcpp_ulong_long_type;
35+
#define RCPP_HAS_LONG_LONG_TYPES
4036
#endif
4137

42-
43-
#if defined(RCPP_HAS_LONG_LONG_TYPES)
44-
45-
namespace Rcpp{
46-
namespace traits{
47-
48-
template<> struct r_sexptype_traits<rcpp_long_long_type>{ enum{ rtype = REALSXP } ; } ;
49-
template<> struct r_sexptype_traits<rcpp_ulong_long_type>{ enum{ rtype = REALSXP } ; } ;
50-
51-
template<> struct r_type_traits<rcpp_long_long_type>{ typedef r_type_primitive_tag r_category ; } ;
52-
template<> struct r_type_traits< std::pair<const std::string,rcpp_long_long_type> >{ typedef r_type_primitive_tag r_category ; } ;
53-
template<> struct r_type_traits<rcpp_ulong_long_type>{ typedef r_type_primitive_tag r_category ; } ;
54-
template<> struct r_type_traits< std::pair<const std::string,rcpp_ulong_long_type> >{ typedef r_type_primitive_tag r_category ; } ;
55-
56-
template <> struct wrap_type_traits<rcpp_long_long_type> { typedef wrap_type_primitive_tag wrap_category; } ;
57-
template <> struct wrap_type_traits<rcpp_ulong_long_type> { typedef wrap_type_primitive_tag wrap_category; } ;
58-
}
59-
}
38+
#endif
6039
#endif
6140

6241
#endif

inst/include/Rcpp/sugar/functions/table.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class Table {
113113
typedef CountInserter<HASH,STORAGE> Inserter ;
114114
HASH hash ;
115115

116-
typedef std::map<STORAGE, int, NAComparator<STORAGE> > SORTED_MAP ;
116+
typedef std::map<STORAGE, int, internal::NAComparator<STORAGE> > SORTED_MAP ;
117117
SORTED_MAP map ;
118118

119119
};

inst/include/Rcpp/traits/is_na.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,13 @@ namespace Rcpp{
3939

4040
template <>
4141
inline bool is_na<REALSXP>(double x) {
42-
return Rcpp_IsNA(x) || Rcpp_IsNaN(x);
42+
return internal::Rcpp_IsNA(x) || internal::Rcpp_IsNaN(x);
4343
}
4444

4545
template <>
4646
inline bool is_na<CPLXSXP>(Rcomplex x) {
47-
return Rcpp_IsNA(x.r) || Rcpp_IsNA(x.i) || Rcpp_IsNaN(x.r) || Rcpp_IsNaN(x.i);
47+
return internal::Rcpp_IsNA(x.r) || internal::Rcpp_IsNA(x.i) ||
48+
internal::Rcpp_IsNaN(x.r) || internal::Rcpp_IsNaN(x.i);
4849
}
4950

5051
template <>

inst/include/Rcpp/traits/is_nan.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ namespace traits{
3333

3434
template <>
3535
inline bool is_nan<REALSXP>( double x ){
36-
return Rcpp_IsNaN(x) ;
36+
return internal::Rcpp_IsNaN(x) ;
3737
}
3838

3939
template <>
4040
inline bool is_nan<CPLXSXP>( Rcomplex x ){
41-
return Rcpp_IsNaN(x.r) || Rcpp_IsNaN(x.i) ;
41+
return internal::Rcpp_IsNaN(x.r) || internal::Rcpp_IsNaN(x.i) ;
4242
}
4343

4444
}

inst/include/Rcpp/traits/longlong.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2+
//
3+
// longlong.h: Rcpp R/C++ interface class library -- long long traits
4+
//
5+
// Copyright (C) 2013 Dirk Eddelbuettel and Romain Francois
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_TRAITS_LONG_LONG_H
23+
#define RCPP_TRAITS_LONG_LONG_H
24+
25+
#if defined(RCPP_HAS_LONG_LONG_TYPES)
26+
27+
namespace Rcpp{
28+
namespace traits{
29+
30+
template<> struct r_sexptype_traits<rcpp_long_long_type>{ enum{ rtype = REALSXP } ; } ;
31+
template<> struct r_sexptype_traits<rcpp_ulong_long_type>{ enum{ rtype = REALSXP } ; } ;
32+
33+
template<> struct r_type_traits<rcpp_long_long_type>{ typedef r_type_primitive_tag r_category ; } ;
34+
template<> struct r_type_traits< std::pair<const std::string,rcpp_long_long_type> >{ typedef r_type_primitive_tag r_category ; } ;
35+
template<> struct r_type_traits<rcpp_ulong_long_type>{ typedef r_type_primitive_tag r_category ; } ;
36+
template<> struct r_type_traits< std::pair<const std::string,rcpp_ulong_long_type> >{ typedef r_type_primitive_tag r_category ; } ;
37+
38+
template <> struct wrap_type_traits<rcpp_long_long_type> { typedef wrap_type_primitive_tag wrap_category; } ;
39+
template <> struct wrap_type_traits<rcpp_ulong_long_type> { typedef wrap_type_primitive_tag wrap_category; } ;
40+
}
41+
}
42+
#endif
43+
44+
#endif

0 commit comments

Comments
 (0)