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 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
|
#pragma once
#include <cmath>
// Android NDK platform < 21 with libstdc++ has spotty C++11 support.
// Various hacks in this header allow the rest of the codebase to use
// standard APIs.
#if (defined(__ANDROID__) && __ANDROID_API__ < 21 && defined(__GLIBCXX__)) || \
defined(__NEWLIB__)
#include <stdexcept>
namespace std {
// Import double versions of these functions from the global namespace.
using ::acosh;
using ::asinh;
using ::atanh;
using ::erf;
using ::erfc;
using ::expm1;
using ::lgamma;
using ::log1p;
using ::nearbyint;
using ::round;
using ::tgamma;
using ::trunc;
using ::truncf;
// Define float versions the same way as more recent libstdc++
inline float acosh(float x) {
return __builtin_acoshf(x);
}
inline float asinh(float x) {
return __builtin_asinhf(x);
}
inline float atanh(float x) {
return __builtin_atanhf(x);
}
inline float copysign(float x, float y) {
return __builtin_copysignf(x, y);
}
inline float erf(float x) {
return __builtin_erff(x);
}
inline float erfc(float x) {
return __builtin_erfcf(x);
}
inline float expm1(float x) {
return __builtin_expm1f(x);
}
inline float fmax(float x, float y) {
return __builtin_fmaxf(x, y);
}
inline float fmin(float x, float y) {
return __builtin_fminf(x, y);
}
inline float lgamma(float x) {
return __builtin_lgammaf(x);
}
inline float log1p(float x) {
return __builtin_log1pf(x);
}
inline float nearbyint(float x) {
return __builtin_nearbyintf(x);
}
inline float remainder(float x, float y) {
return __builtin_remainderf(x, y);
}
inline float round(float x) {
return __builtin_roundf(x);
}
inline float tgamma(float x) {
return __builtin_tgammaf(x);
}
inline float trunc(float x) {
return __builtin_truncf(x);
}
// __builtin_nexttoward isn't doesn't work. It appears to try to
// link against the global nexttoward function, which is not present
// prior to API 18. Just bail for now.
inline float nexttoward(float x, long double y) {
throw std::runtime_error("std::nexttoward is not present on older Android");
}
inline double nexttoward(double x, long double y) {
throw std::runtime_error("std::nexttoward is not present on older Android");
}
#if !defined(__NEWLIB__)
// TODO: this function needs to be implemented and tested. Currently just throw
// an error.
inline float hypot(float x, float y) {
throw std::runtime_error("std::hypot is not implemented on older Android");
}
inline double hypot(double x, double y) {
throw std::runtime_error("std::hypot is not implemented on older Android");
}
#else
inline float hypot(float x, float y) {
return hypot((double)x, (double)y);
}
#endif
// TODO: this function needs to be implemented and tested. Currently just throw
// an error.
inline float igamma(float x, float y) {
throw std::runtime_error("igamma is not implemented on older Android");
}
inline double igamma(double x, double y) {
throw std::runtime_error("igamma is not implemented on older Android");
}
inline float igammac(float x, float y) {
throw std::runtime_error("igammac is not implemented on older Android");
}
inline double igammac(double x, double y) {
throw std::runtime_error("igammac is not implemented on older Android");
}
// Note: std::signbit returns true for negative zero (-0), but this
// implementation returns false.
inline bool signbit(float x) {
return x < 0;
}
inline bool signbit(double x) {
return x < 0;
}
inline bool signbit(long double x) {
return x < 0;
}
#if !defined(__NEWLIB__)
// TODO: this function needs to be implemented and tested. Currently just throw
// an error.
inline float nextafter(float x, float y) {
throw std::runtime_error(
"std::nextafter is not implemented on older Android");
}
inline double nextafter(double x, double y) {
throw std::runtime_error(
"std::nextafter is not implemented on older Android");
}
#else
inline float nextafter(float x, float y) {
return nextafter((double)x, (double)y);
}
#endif
#if !defined(__NEWLIB__)
// TODO: this function needs to be implemented and tested. Currently just throw
// an error.
inline float exp2(float x) {
throw std::runtime_error("std::exp2 is not implemented on older Android");
}
inline double exp2(double x) {
throw std::runtime_error("std::exp2 is not implemented on older Android");
}
#else
inline float exp2(float x) {
return exp2((double)x);
}
#endif
// Define integral versions the same way as more recent libstdc++
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type acosh(T x) {
return __builtin_acosh(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type asinh(T x) {
return __builtin_asinh(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type atanh(T x) {
return __builtin_atanh(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type erf(T x) {
return __builtin_erf(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type erfc(T x) {
return __builtin_erfc(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type expm1(T x) {
return __builtin_expm1(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type lgamma(T x) {
return __builtin_lgamma(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type log1p(T x) {
return __builtin_log1p(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type nearbyint(
T x) {
return __builtin_nearbyint(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type round(T x) {
return __builtin_round(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type tgamma(T x) {
return __builtin_tgamma(x);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type trunc(T x) {
return __builtin_trunc(x);
}
// Convoluted definition of these binary functions for overloads other than
// (float,float) and (double,double). Using a template from __gnu_cxx
// is dirty, but this code is only enabled on a dead platform, so there
// shouldn't be any risk of it breaking due to updates.
template <typename T, typename U>
typename __gnu_cxx::__promote_2<T, U>::__type fmax(T x, U y) {
typedef typename __gnu_cxx::__promote_2<T, U>::__type type;
return fmax(type(x), type(y));
}
template <typename T, typename U>
typename __gnu_cxx::__promote_2<T, U>::__type fmin(T x, U y) {
typedef typename __gnu_cxx::__promote_2<T, U>::__type type;
return fmin(type(x), type(y));
}
template <typename T, typename U>
typename __gnu_cxx::__promote_2<T, U>::__type copysign(T x, U y) {
typedef typename __gnu_cxx::__promote_2<T, U>::__type type;
return copysign(type(x), type(y));
}
template <typename T, typename U>
typename __gnu_cxx::__promote_2<T, U>::__type remainder(T x, U y) {
typedef typename __gnu_cxx::__promote_2<T, U>::__type type;
return remainder(type(x), type(y));
}
// log2 is a macro on Android API < 21, so we need to define it ourselves.
inline float log2(float arg) {
return ::log(arg) / ::log(2.0);
}
#if !defined(__NEWLIB__)
inline double log2(double arg) {
return ::log(arg) / ::log(2.0);
}
#endif
inline long double log2(long double arg) {
return ::log(arg) / ::log(2.0);
}
template <typename T>
typename std::enable_if<std::is_integral<T>::value, double>::type log2(T x) {
return ::log(x) / ::log(2.0);
}
} // namespace std
#endif
|