1 // Copyright 2017 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_ 16 #define ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_ 17 18 #include <cmath> 19 #include <iostream> 20 #include <limits> 21 #include <type_traits> 22 23 #include "absl/meta/type_traits.h" 24 #include "absl/numeric/int128.h" 25 26 namespace absl { 27 ABSL_NAMESPACE_BEGIN 28 namespace random_internal { 29 30 // The null_state_saver does nothing. 31 template <typename T> 32 class null_state_saver { 33 public: 34 using stream_type = T; 35 using flags_type = std::ios_base::fmtflags; 36 null_state_saver(T &,flags_type)37 null_state_saver(T&, flags_type) {} ~null_state_saver()38 ~null_state_saver() {} 39 }; 40 41 // ostream_state_saver is a RAII object to save and restore the common 42 // basic_ostream flags used when implementing `operator <<()` on any of 43 // the absl random distributions. 44 template <typename OStream> 45 class ostream_state_saver { 46 public: 47 using ostream_type = OStream; 48 using flags_type = std::ios_base::fmtflags; 49 using fill_type = typename ostream_type::char_type; 50 using precision_type = std::streamsize; 51 ostream_state_saver(ostream_type & os,flags_type flags,fill_type fill)52 ostream_state_saver(ostream_type& os, // NOLINT(runtime/references) 53 flags_type flags, fill_type fill) 54 : os_(os), 55 flags_(os.flags(flags)), 56 fill_(os.fill(fill)), 57 precision_(os.precision()) { 58 // Save state in initialized variables. 59 } 60 ~ostream_state_saver()61 ~ostream_state_saver() { 62 // Restore saved state. 63 os_.precision(precision_); 64 os_.fill(fill_); 65 os_.flags(flags_); 66 } 67 68 private: 69 ostream_type& os_; 70 const flags_type flags_; 71 const fill_type fill_; 72 const precision_type precision_; 73 }; 74 75 #if defined(__NDK_MAJOR__) && __NDK_MAJOR__ < 16 76 #define ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 1 77 #else 78 #define ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 0 79 #endif 80 81 template <typename CharT, typename Traits> 82 ostream_state_saver<std::basic_ostream<CharT, Traits>> make_ostream_state_saver( 83 std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references) 84 std::ios_base::fmtflags flags = std::ios_base::dec | std::ios_base::left | 85 #if ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 86 std::ios_base::fixed | 87 #endif 88 std::ios_base::scientific) { 89 using result_type = ostream_state_saver<std::basic_ostream<CharT, Traits>>; 90 return result_type(os, flags, os.widen(' ')); 91 } 92 93 template <typename T> 94 typename absl::enable_if_t<!std::is_base_of<std::ios_base, T>::value, 95 null_state_saver<T>> 96 make_ostream_state_saver(T& is, // NOLINT(runtime/references) 97 std::ios_base::fmtflags flags = std::ios_base::dec) { 98 std::cerr << "null_state_saver"; 99 using result_type = null_state_saver<T>; 100 return result_type(is, flags); 101 } 102 103 // stream_precision_helper<type>::kPrecision returns the base 10 precision 104 // required to stream and reconstruct a real type exact binary value through 105 // a binary->decimal->binary transition. 106 template <typename T> 107 struct stream_precision_helper { 108 // max_digits10 may be 0 on MSVC; if so, use digits10 + 3. 109 static constexpr int kPrecision = 110 (std::numeric_limits<T>::max_digits10 > std::numeric_limits<T>::digits10) 111 ? std::numeric_limits<T>::max_digits10 112 : (std::numeric_limits<T>::digits10 + 3); 113 }; 114 115 template <> 116 struct stream_precision_helper<float> { 117 static constexpr int kPrecision = 9; 118 }; 119 template <> 120 struct stream_precision_helper<double> { 121 static constexpr int kPrecision = 17; 122 }; 123 template <> 124 struct stream_precision_helper<long double> { 125 static constexpr int kPrecision = 36; // assuming fp128 126 }; 127 128 // istream_state_saver is a RAII object to save and restore the common 129 // std::basic_istream<> flags used when implementing `operator >>()` on any of 130 // the absl random distributions. 131 template <typename IStream> 132 class istream_state_saver { 133 public: 134 using istream_type = IStream; 135 using flags_type = std::ios_base::fmtflags; 136 137 istream_state_saver(istream_type& is, // NOLINT(runtime/references) 138 flags_type flags) 139 : is_(is), flags_(is.flags(flags)) {} 140 141 ~istream_state_saver() { is_.flags(flags_); } 142 143 private: 144 istream_type& is_; 145 flags_type flags_; 146 }; 147 148 template <typename CharT, typename Traits> 149 istream_state_saver<std::basic_istream<CharT, Traits>> make_istream_state_saver( 150 std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references) 151 std::ios_base::fmtflags flags = std::ios_base::dec | 152 std::ios_base::scientific | 153 std::ios_base::skipws) { 154 using result_type = istream_state_saver<std::basic_istream<CharT, Traits>>; 155 return result_type(is, flags); 156 } 157 158 template <typename T> 159 typename absl::enable_if_t<!std::is_base_of<std::ios_base, T>::value, 160 null_state_saver<T>> 161 make_istream_state_saver(T& is, // NOLINT(runtime/references) 162 std::ios_base::fmtflags flags = std::ios_base::dec) { 163 using result_type = null_state_saver<T>; 164 return result_type(is, flags); 165 } 166 167 // stream_format_type<T> is a helper struct to convert types which 168 // basic_iostream cannot output as decimal numbers into types which 169 // basic_iostream can output as decimal numbers. Specifically: 170 // * signed/unsigned char-width types are converted to int. 171 // * TODO(lar): __int128 => uint128, except there is no operator << yet. 172 // 173 template <typename T> 174 struct stream_format_type 175 : public std::conditional<(sizeof(T) == sizeof(char)), int, T> {}; 176 177 // stream_u128_helper allows us to write out either absl::uint128 or 178 // __uint128_t types in the same way, which enables their use as internal 179 // state of PRNG engines. 180 template <typename T> 181 struct stream_u128_helper; 182 183 template <> 184 struct stream_u128_helper<absl::uint128> { 185 template <typename IStream> 186 inline absl::uint128 read(IStream& in) { 187 uint64_t h = 0; 188 uint64_t l = 0; 189 in >> h >> l; 190 return absl::MakeUint128(h, l); 191 } 192 193 template <typename OStream> 194 inline void write(absl::uint128 val, OStream& out) { 195 uint64_t h = absl::Uint128High64(val); 196 uint64_t l = absl::Uint128Low64(val); 197 out << h << out.fill() << l; 198 } 199 }; 200 201 #ifdef ABSL_HAVE_INTRINSIC_INT128 202 template <> 203 struct stream_u128_helper<__uint128_t> { 204 template <typename IStream> 205 inline __uint128_t read(IStream& in) { 206 uint64_t h = 0; 207 uint64_t l = 0; 208 in >> h >> l; 209 return (static_cast<__uint128_t>(h) << 64) | l; 210 } 211 212 template <typename OStream> 213 inline void write(__uint128_t val, OStream& out) { 214 uint64_t h = static_cast<uint64_t>(val >> 64u); 215 uint64_t l = static_cast<uint64_t>(val); 216 out << h << out.fill() << l; 217 } 218 }; 219 #endif 220 221 template <typename FloatType, typename IStream> 222 inline FloatType read_floating_point(IStream& is) { 223 static_assert(std::is_floating_point<FloatType>::value, ""); 224 FloatType dest; 225 is >> dest; 226 // Parsing a double value may report a subnormal value as an error 227 // despite being able to represent it. 228 // See https://stackoverflow.com/q/52410931/3286653 229 // It may also report an underflow when parsing DOUBLE_MIN as an 230 // ERANGE error, as the parsed value may be smaller than DOUBLE_MIN 231 // and rounded up. 232 // See: https://stackoverflow.com/q/42005462 233 if (is.fail() && 234 (std::fabs(dest) == (std::numeric_limits<FloatType>::min)() || 235 std::fpclassify(dest) == FP_SUBNORMAL)) { 236 is.clear(is.rdstate() & (~std::ios_base::failbit)); 237 } 238 return dest; 239 } 240 241 } // namespace random_internal 242 ABSL_NAMESPACE_END 243 } // namespace absl 244 245 #endif // ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_ 246