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